//	Simple test cases for the threads assignment.
//
#include <stdlib.h> //used for random number generation
#include <time.h> //used for random number generation
#include "math.h"
#include "copyright.h"
#include "system.h"
#ifdef CHANGED
#include "synch.h"
#endif

#ifdef CHANGED
//=================================================//
//----------------------CONST----------------------//
//=================================================//

	const int MAX_CASHIERS = 5;
	const int MAX_GOODS_LOADERS = 5;
	const int MAX_SALESMAN = 3;
	const int MAX_DEPARTMENTS = 5;
	const int MAX_CUSTOMERS = 30;
//=================================================//
//---------------------STRUCTS---------------------//
//=================================================//
/*
	All of our structs will go here, Will be broken
	down into smaller sections
*/

//////////////////////
//Humans
//////////////////////
typedef struct Trolly{
	//All trolly data goes here
	int itemList[MAX_DEPARTMENTS];
} Trolly;

typedef struct Customer{
	//All customer data goes here
	int identifier;
	int privileged; //0 = not, 1 = privileged
	int itemList[MAX_DEPARTMENTS]; //up to MAX_DEPARTMENTS
	Trolly trolly;
	int money;
	int bill;
	int cashierID;
	int numItemsOnList;
	int canPay;
	int readyToNegotiate;
} Customer;

typedef struct Cashier{
	//All cashier data goes here
	int identifier;
	int goOnBreak; //0 = do not go on break, 1 = go on break when current customer has been served
	int onBreak; //0 = not on break, 1 = on break //used by customers to determine whether they are being called forward or told to disperse
	int servingCustomer; //0 = free, 1 = currently serving customer
	int cashierLineCount;
	int cashierPrivilegedLineCount;
	int customerID;
	
	Lock* checkOrModifyLinesLock;
	Lock* cashierLock;
	Condition* cashierCV;
	Lock* cashierLineLock;
	Condition* cashierLineCV;
	Lock* cashierPrivilegedLineLock;
	Condition* cashierPrivilegedLineCV;
} Cashier;

typedef struct GoodsLoader{
	//All goods loader data goes here
	int identifier;
	int departmentToRestock;
	int itemToRestock;
	int salesmanToNotifyAfterRestock;
	int numberOfItems;
	//Lock* goodsLoaderLock;
	Condition* goodsLoaderCV;
} GoodsLoader;

typedef struct Salesman{
	//All salesman data goes here
	int identifier;
	int departmentNumber;
	int goOnBreak;
	Lock* salesmanLock;
	Condition* salesmanCV;
	Condition* salesmanOnBreakCV;
} Salesman;

typedef struct Manager{
	//All manager data goes here
	int currentCashierID;
	int totalSales;
	int itemToRemove;
	int steps;
	int stepsUntilEmptyingDrawers;
	int stepsUntilStatingTotalSales;
	int stepsUntilSendingCashierOnBreak;
	int stepsUntilSendingSalesmanOnBreak;
	Lock* managerLock;
	Condition* managerCV;
	Condition* managerCashierLineCV;
	Condition* managerCashierHelpCV;
} Manager;

//////////////////////
//Department Utilities
//////////////////////
typedef struct CheckoutCounter{
	//All cashiers counter data goes here
	int identifier;
	int moneyInDrawer;
	int totalCounterSales;
	Lock* drawerLock;
} CheckoutCounter;

typedef struct Department{
	//All department data goes here
	int identifier;
	Salesman* listOfSalesman[MAX_SALESMAN];
	int numberOfItems;
	int customerWaitingLineCount;
	int goodsLoaderWaitingLineCount;
	int restockAlreadyRequested;
	int salesCustIdentifier[MAX_SALESMAN];
	int salesLoaderIdentifier[MAX_SALESMAN];
	/*This is the array that stores which type of person the salesman is currently talking to
	0 = Greeting Customer, 1 = Complaining Customer, 2 = Goods Loader*/
	int whomITalkTo[3];
	Lock* shelfLock;
	Lock* goodsLoaderWaitingForSalesLock;
	Lock* custWaitingForSalesLock;
	Lock* restockAlreadyRequestedLock;
	Lock* departmentRestockLock;
	Condition* shelfCV;
	Condition* goodsLoaderWaitingForSalesCV;
	Condition* custWaitingForSalesCV;
	Condition* custWaitingForRestockCV;
	/*This is the status array of all salesmen in the department. 
	0 = FREE, 1 = BUSY, 2 = ONBREAK, 3 = READY TO SPEAK TO A CUSTOMER */
	int salesStatusArray[MAX_SALESMAN]; 
} Department;
//=================================================//
//------------------(END) STRUCTS------------------//
//=================================================//

//=================================================//
//-----------------GLOBAL DATA---------------------//
//=================================================//
/*
	All of our globals will go here, Will be broken
	down into smaller sections
*/
	Manager* manager;
	Customer* customerArray[MAX_CUSTOMERS];
	Department* departmentArray[MAX_DEPARTMENTS];
	Cashier* cashierArray[MAX_CASHIERS];
	Lock* stockRoomLock;
	int goodsLoaderInStockRoom = -1;
	CheckoutCounter* checkoutCounterArray[MAX_CASHIERS];
	GoodsLoader* goodsLoaderArray[MAX_GOODS_LOADERS];
	int pricesOfItems[MAX_DEPARTMENTS];
	int MIN_PRICE = 1;
	int MAX_PRICE = 5;
	Lock* trollyLineLock;
	Condition* trollyLineCV;
	int numTrolly = 20;
	Lock* cashierLinesLock;
	Lock* salesLoaderRestockLock;
	/*This is the status array of all goodsloaders. 
	0 = FREE, 1 = NEEDS TO GO TO STOCKROOM, 2 = IN STOCKROOM, 3 = WALKING TO DEPARTMENT, 4 = NEEDS TO RESTOCK SHELF, 5 = NEEDS TO NOTIFY SALESMAN, 6 = SALESMAN NOTIFIED */
	int goodsLoaderStatus[MAX_GOODS_LOADERS];
	int salesmanOrderedRestock[MAX_GOODS_LOADERS];
	int whichDepartmentToRestock[MAX_GOODS_LOADERS];
	int remainingCustomers;
	int departmentsToRestock[MAX_DEPARTMENTS];
	
	
	int NUM_CASHIERS;
	int NUM_GOODS_LOADERS;
	int NUM_MANAGERS;
	int NUM_SALESMAN;
	int NUM_DEPARTMENTS;
	int NUM_TOTAL_CUSTOMERS;
	int NUM_ITEMS_ON_SHELF;
	int CUSTOMER_MONEY;
	
	int NUM_PRIVILEGED_CUSTOMERS = 0; //incremented by CustomerSetup
	int NUM_CUSTOMERS = 0; //incremented by CustomerSetup
	bool debugShowCustomerOutput = false;
	bool debugShowCashierOutput = false;
	bool debugShowSalesmanOutput = false;
	bool debugShowGoodsLoaderOutput = false;
	bool debugShowManagerOutput = false;
//=================================================//
//--------------(END) GLOBAL DATA------------------//
//=================================================//

//=================================================//
//-------------MISCELLANEOUS FUNCTIONS-------------//
//=================================================//
	//All of our miscellaneous functions will go here
	void debugPrint(char* debugOutput)
	{
		bool showThisOutput = true;
		switch(currentThread->getName()[3])
		{
			case 't':
				if (!debugShowCustomerOutput)
					showThisOutput = false;
				break;
			case 'h':
				if (!debugShowCashierOutput)
					showThisOutput = false;
				break;
			case 'e':
				if (!debugShowSalesmanOutput)
					showThisOutput = false;
				break;
			case 'd':
				if (!debugShowGoodsLoaderOutput)
					showThisOutput = false;
				break;
			case 'a':
				if (!debugShowManagerOutput)
					showThisOutput = false;
				break;
			default:
				printf("\n~~DEBUG output from unknown thread!~~\n\n");
				break;
		}
		if (showThisOutput)
			printf("~~DEBUG: {%s}: \"%s\"\n",currentThread->getName(),debugOutput);
	}
	void debugPrint(char* debugOutput, int debugInt)
	{
		bool showThisOutput = true;
		switch(currentThread->getName()[3])
		{
			case 't':
				if (!debugShowCustomerOutput)
					showThisOutput = false;
				break;
			case 'h':
				if (!debugShowCashierOutput)
					showThisOutput = false;
				break;
			case 'e':
				if (!debugShowSalesmanOutput)
					showThisOutput = false;
				break;
			case 'd':
				if (!debugShowGoodsLoaderOutput)
					showThisOutput = false;
				break;
			case 'a':
				if (!debugShowManagerOutput)
					showThisOutput = false;
				break;
			default:
				printf("\n~~DEBUG output from unknown thread!~~\n\n");
				break;
		}
		if (showThisOutput)
			printf("~~DEBUG: {%s}: \"%s {%d}\"\n",currentThread->getName(),debugOutput,debugInt);
	}
	void debugPrint(char* debugOutput, int debugInt,int debugInt2)
	{
		bool showThisOutput = true;
		switch(currentThread->getName()[3])
		{
			case 't':
				if (!debugShowCustomerOutput)
					showThisOutput = false;
				break;
			case 'h':
				if (!debugShowCashierOutput)
					showThisOutput = false;
				break;
			case 'e':
				if (!debugShowSalesmanOutput)
					showThisOutput = false;
				break;
			case 'd':
				if (!debugShowGoodsLoaderOutput)
					showThisOutput = false;
				break;
			case 'a':
				if (!debugShowManagerOutput)
					showThisOutput = false;
				break;
			default:
				printf("\n~~DEBUG output from unknown thread!~~\n\n");
				break;
		}
		if (showThisOutput)
			printf("~~DEBUG: {%s}: \"%s {%d, %d}\"\n",currentThread->getName(),debugOutput,debugInt,debugInt2);
	}
	char* convertToDollarsAndCents(int totalCents)
	{
		int dollars = totalCents/100;
		int cents = (totalCents-((totalCents/100)*100));
		char *dollarsAndCents = (char *)malloc(64 * sizeof(char*));
		if (cents<10)
		{
			sprintf(dollarsAndCents,"%d.0%d",dollars,cents);
		}
		else
		{
			sprintf(dollarsAndCents,"%d.%d",dollars,cents);
		}
		return dollarsAndCents;
	}
	void printEndOfSimulationOutputs()
	{
		//allow goodsloaders to finish restocking things
		for (int i = 0; i < NUM_GOODS_LOADERS; i++)
			if (goodsLoaderStatus[i] != 0)
				for (int j = 0; j < 50; j++)
					currentThread->Yield();
		
		for (int i = 0; i < NUM_CASHIERS; i++)
				for (int j = 0; j < 50; j++)
					currentThread->Yield();
		int totalSalesEOS = 0;
		for (int k = 0; k < NUM_CASHIERS; k++)
		{
			totalSalesEOS += checkoutCounterArray[k]->totalCounterSales;
			printf("Total Sale from Counter [%d] is $[%s].\n",k,convertToDollarsAndCents(checkoutCounterArray[k]->totalCounterSales));
		}
		printf("Total Sale of the entire store is $[%s].\n",convertToDollarsAndCents(totalSalesEOS));
	}
	int randInt(int min, int max)
	{			
		return (rand() % (max - min + 1) + min); //returns a random int in the specified range
	}
	
	float randFloat(int min, int max)
	{	
		//generates a seed for rand() based on time
		//only happens once
		static int seeded = 0;
  		if (seeded == 0)
		{
			srand(time(NULL));
			seeded = 1;
		}
		
		return (floor((rand() % ((max*100) - (min*100) + 1) + (min*100))+0.5))/100; //returns a random float in the specified range rounded to nearest hundreth
	}
//=================================================//
//---------(END) MISCELLANEOUS FUNCTIONS-----------//
//=================================================//

//=================================================//
//------------------CUSTOMER-----------------------//
//=================================================//
void CustomerSetup(Customer *c, int id){ //called when initializing a new Customer
	c->identifier = id;
	
	//1 in 5 chance of a customer being privileged
	if(randInt(1, 5) != 1)
	{
		c->privileged = 0;
		NUM_CUSTOMERS++;
	}
	else
	{
		c->privileged = 1;
		NUM_PRIVILEGED_CUSTOMERS++;
	}
	
	c->money = CUSTOMER_MONEY;
	c->cashierID = -1;
	c->canPay = 1;
	c->readyToNegotiate = 0;
	
	//populate customer's item list
	c->numItemsOnList = randInt(1, 10);
	for(int i = 0; i < c->numItemsOnList; i++)
	{
		int itemType = randInt(0, NUM_DEPARTMENTS-1);
		c->itemList[itemType]++;
	}
	
}

void CustomerFunction(int id){
	//print that customer has entered
	if(customerArray[id]->privileged)
		printf("PrivilegedCustomer [%d] enters the SuperMarket\n", id);
	else
		printf("Customer [%d] enters the SuperMarket\n", id);
	
	//print how many items the customer wants to buy
	if(customerArray[id]->privileged)
		printf("PrivilegedCustomer [%d] wants to buy [%d] no.of items.\n", id, customerArray[id]->numItemsOnList);
	else
		printf("Customer [%d] wants to buy [%d] no.of items.\n", id, customerArray[id]->numItemsOnList);
	
	//print how many of each type of item the customer wants to buy
	for(int i = 0; i < NUM_DEPARTMENTS; i++)
	{
		if(customerArray[id]->itemList[i] > 0)
		{
			if(customerArray[id]->privileged)
				printf("PrivilegedCustomer [%d] wants to buy [item%d]-[%d].\n", id, i, customerArray[id]->itemList[i]);
			else
				printf("Customer [%d] wants to buy [item%d]-[%d].\n", id, i, customerArray[id]->itemList[i]);
		}
	}
	
	//wait in line for a trolly if necessary
	trollyLineLock->Acquire();
	if(numTrolly == 0)
	{
		if(customerArray[id]->privileged)
			printf("PrivilegedCustomer [%d] gets in line for a trolly\n", id);
		else
			printf("Customer [%d] gets in line for a trolly\n", id);
		trollyLineCV->Wait(trollyLineLock);
	}
	
	//get and initialize the customer's trolly
	if(customerArray[id]->privileged)
		printf("PrivilegedCustomer [%d] has a trolly for shopping\n", id);
	else
		printf("Customer [%d] has a trolly for shopping\n", id);
	numTrolly--;
	trollyLineLock->Release();
	for(int i = 0; i < NUM_DEPARTMENTS; i++)
	{
		customerArray[id]->trolly.itemList[i] = 0;
	}
	
	//find each item on list
	for(int i = 0; i < NUM_DEPARTMENTS; i++)
	{
		//if the item type is on the customer's list they must go to that department
		if(customerArray[id]->itemList[i] > 0)
		{
			//print which department the customer is headed to
			if(customerArray[id]->privileged)
				printf("PrivilegedCustomer [%d] wants to shop in Department[%d]\n", id, i);
			else
				printf("Customer [%d] wants to shop in Department[%d]\n", id, i);
			
			//find a salesman
			departmentArray[i]->custWaitingForSalesLock->Acquire();
			bool waitInLine = 1;
			for(int j = 0; j < NUM_SALESMAN; j++) //check with each department salesman
			{
				//if there is a free salesman, begin interaction with that salesman and skip the line
				departmentArray[i]->listOfSalesman[j]->salesmanLock->Acquire();
				debugPrint("Checking sales status %d, customerWaitingLineCount %d",departmentArray[i]->salesStatusArray[j], departmentArray[i]->customerWaitingLineCount);
				if(departmentArray[i]->salesStatusArray[j] == 0 && departmentArray[i]->customerWaitingLineCount == 0 && departmentArray[i]->listOfSalesman[j]->goOnBreak == 0)
				{
					waitInLine = 0;
					departmentArray[i]->salesStatusArray[j] = 1;
					departmentArray[i]->salesCustIdentifier[j] = id;
					departmentArray[i]->whomITalkTo[j] = 0;
					departmentArray[i]->custWaitingForSalesLock->Release();
					if(customerArray[id]->privileged)
						printf("PrivilegedCustomer [%d] is interacting with DepartmentSalesman[%d] of Department[%d]\n", id, j, i);
					else
						printf("Customer [%d] is interacting with DepartmentSalesman[%d] of Department[%d]\n", id, j, i);
					debugPrint("-A- signaling salesmanlock %d",departmentArray[i]->salesStatusArray[j]);
					departmentArray[i]->listOfSalesman[j]->salesmanCV->Signal(departmentArray[i]->listOfSalesman[j]->salesmanLock);
					debugPrint("-A- waiting on salesmanlock %d",departmentArray[i]->salesStatusArray[j]);
					departmentArray[i]->listOfSalesman[j]->salesmanCV->Wait(departmentArray[i]->listOfSalesman[j]->salesmanLock);
					debugPrint("woken on salesmanlock");
					debugPrint("Setting salesman status.");
					departmentArray[i]->salesStatusArray[j] = 0;
					debugPrint("salesman status set.");
					departmentArray[i]->listOfSalesman[j]->salesmanLock->Release();
					debugPrint("released salesmanlock");
					break;
				}
				else
				{
					departmentArray[i]->listOfSalesman[j]->salesmanLock->Release();
				}
				
			}
			
			//if there was not a free salesman
			if(waitInLine)
			{
				//get in line and wait to be called up by a salesman
				for(int j = 0; j < NUM_SALESMAN; j++)
				{
					departmentArray[i]->listOfSalesman[j]->salesmanLock->Acquire();
				}
				departmentArray[i]->customerWaitingLineCount++;
				debugPrint("Incremented customerWaitingLineCount to ",departmentArray[i]->customerWaitingLineCount);
				if(customerArray[id]->privileged)
					printf("PrivilegedCustomer [%d] gets in line for the Department [%d]\n", id, i);
				else
					printf("Customer [%d] gets in line for the Department [%d]\n", id, i);
				for(int j = 0; j < NUM_SALESMAN; j++)
				{
					departmentArray[i]->listOfSalesman[j]->salesmanLock->Release();
				}
				departmentArray[i]->custWaitingForSalesCV->Wait(departmentArray[i]->custWaitingForSalesLock);
				debugPrint("waiting in line has woken up.");
				//check with each department salesman
				for(int j = 0; j < NUM_SALESMAN; j++)
				{
					//if the corresponding department salesman is the one who called the customer up, begin interacting with the salesman
					departmentArray[i]->listOfSalesman[j]->salesmanLock->Acquire();
					debugPrint("checking salesman status: salesman status =%d.", departmentArray[i]->salesStatusArray[j]);
					if((departmentArray[i]->salesStatusArray[j] == 3 || departmentArray[i]->salesStatusArray[j] == 0 ) && departmentArray[i]->whomITalkTo[j] != 2 && departmentArray[i]->listOfSalesman[j]->goOnBreak == 0)
					{
						
						
						departmentArray[i]->salesStatusArray[j] = 1;
						departmentArray[i]->salesCustIdentifier[j] = id;
						departmentArray[i]->whomITalkTo[j] = 0;
						departmentArray[i]->custWaitingForSalesLock->Release();
						if(customerArray[id]->privileged)
							printf("PrivilegedCustomer [%d] is interacting with DepartmentSalesman[%d] of Department[%d]\n", id, j, i);
						else
							printf("Customer [%d] is interacting with DepartmentSalesman[%d] of Department[%d]\n", id, j, i);
						debugPrint("-B- signaling salesmanlock %d",departmentArray[i]->salesStatusArray[j]);
						departmentArray[i]->listOfSalesman[j]->salesmanCV->Signal(departmentArray[i]->listOfSalesman[j]->salesmanLock);
						debugPrint("-B- waiting on salesmanlock %d",departmentArray[i]->salesStatusArray[j]);
						departmentArray[i]->listOfSalesman[j]->salesmanCV->Wait(departmentArray[i]->listOfSalesman[j]->salesmanLock);
						debugPrint("Setting salesman status.");
						departmentArray[i]->salesStatusArray[j] = 0;
						debugPrint("salesman status set.");
						departmentArray[i]->listOfSalesman[j]->salesmanLock->Release();
						break;
					}
					else
					{
						departmentArray[i]->listOfSalesman[j]->salesmanLock->Release();
					}
				}
			}
			
			while(customerArray[id]->itemList[i] > 0)
			{
				//access the shelf with the item the customer is looking for
				departmentArray[i]->shelfLock->Acquire();
				if(customerArray[id]->itemList[i] <= departmentArray[i]->numberOfItems) //if the shelf has enough of the item that the customer wants
				{
					//take the item off the shelf and put it in the trolly
					departmentArray[i]->numberOfItems -= customerArray[id]->itemList[i];
					customerArray[id]->trolly.itemList[i] += customerArray[id]->itemList[i];
					if(customerArray[id]->privileged)
						printf("PrivilegedCustomer [%d] has found [item%d] and placed [%d] in the trolly\n", id, i, customerArray[id]->itemList[i]);
					else
						printf("Customer [%d] has found [item%d] and placed [%d] in the trolly\n", id, i, customerArray[id]->itemList[i]);
					customerArray[id]->itemList[i] = 0;
					debugPrint("%d ITEMS ON SHELF", departmentArray[i]->numberOfItems);
					departmentArray[i]->shelfLock->Release();
				}
				else //if the shelf does not have enough of the item that the customer wants
				{
					//take as many of that item as there are on that shelf
					if(departmentArray[i]->numberOfItems > 0)
					{
						customerArray[id]->trolly.itemList[i] += departmentArray[i]->numberOfItems;
						customerArray[id]->itemList[i] -= departmentArray[i]->numberOfItems;
						if(customerArray[id]->privileged)
							printf("PrivilegedCustomer [%d] has found [item%d] and placed [%d] in the trolly\n", id, i, departmentArray[i]->numberOfItems);
						else
							printf("Customer [%d] has found [item%d] and placed [%d] in the trolly\n", id, i, departmentArray[i]->numberOfItems);
						departmentArray[i]->numberOfItems = 0;
						debugPrint("%d ITEMS ON SHELF", departmentArray[i]->numberOfItems);
					}
					
					debugPrint("finding salesman to restock");
					//find a salesman
					departmentArray[i]->custWaitingForSalesLock->Acquire();
					debugPrint("acquired custwaitingforsaleslock");
					departmentArray[i]->shelfLock->Release();
					debugPrint("released shelflock");
					bool waitInLineForRestock = 1;
					for(int j = 0; j < NUM_SALESMAN; j++) //look through the salesmans
					{
						//if there is a free salesman, tell him that the item the customer wants is out of stock and wait for it to be restocked
						
						departmentArray[i]->listOfSalesman[j]->salesmanLock->Acquire();
						debugPrint("-1- checking salesman %d, status %d",j,departmentArray[i]->salesStatusArray[j]);
						if(departmentArray[i]->salesStatusArray[j] == 0 && departmentArray[i]->customerWaitingLineCount == 0 && departmentArray[i]->listOfSalesman[j]->goOnBreak == 0)
						{
							waitInLineForRestock = 0;
							
							departmentArray[i]->departmentRestockLock->Acquire();
							departmentArray[i]->salesStatusArray[j] = 1;
							departmentArray[i]->salesCustIdentifier[j] = id;
							departmentArray[i]->whomITalkTo[j] = 1;
							departmentArray[i]->custWaitingForSalesLock->Release();
							printf("Customer [%d] is asking for assistance from DepartmentSalesman [%d].\n", id, j);
							debugPrint("A: %d %d", i, j);
							departmentArray[i]->listOfSalesman[j]->salesmanCV->Signal(departmentArray[i]->listOfSalesman[j]->salesmanLock);
							debugPrint("B");
							departmentArray[i]->salesStatusArray[j] = 0;
							debugPrint("C");
							departmentArray[i]->listOfSalesman[j]->salesmanLock->Release();
							departmentArray[i]->custWaitingForRestockCV->Wait(departmentArray[i]->departmentRestockLock);
							debugPrint("D");
							departmentArray[i]->departmentRestockLock->Release();
							printf("Customer [%d] has received assistance about restocking of [item%d] from DepartmentSalesman [%d].\n", id, i, j);
							break;
						}
						else
						{
							departmentArray[i]->listOfSalesman[j]->salesmanLock->Release();
						}
					}
					
					//if there was not a free salesman
					if(waitInLineForRestock)
					{debugPrint("getting in line");
						//get in line and wait to be called up by a salesman
						departmentArray[i]->customerWaitingLineCount++;
						debugPrint("Incremented customerWaitingLineCount to ",departmentArray[i]->customerWaitingLineCount);
						debugPrint("about to wait on custwaitingforsalescv, custwaitingforsaleslock");
						departmentArray[i]->custWaitingForSalesCV->Wait(departmentArray[i]->custWaitingForSalesLock);
						debugPrint("about to woke up from custwaitingforsalescv, custwaitingforsaleslock");
						//check with each department salesman
						for(int j = 0; j < NUM_SALESMAN; j++)
						{
							//if the corresponding department salesman is the one who called the customer up, tell them the item needs to be restocked and wait for it to be restocked
							
							departmentArray[i]->listOfSalesman[j]->salesmanLock->Acquire();
							debugPrint("-2- checking salesman %d, status %d",j,departmentArray[i]->salesStatusArray[j]);
							if((departmentArray[i]->salesStatusArray[j] == 3 || departmentArray[i]->salesStatusArray[j] == 0 ) && departmentArray[i]->whomITalkTo[j] != 2 && departmentArray[i]->listOfSalesman[j]->goOnBreak == 0)
							{
								
								departmentArray[i]->departmentRestockLock->Acquire();
								departmentArray[i]->salesStatusArray[j] = 1;
								departmentArray[i]->salesCustIdentifier[j] = id;
								departmentArray[i]->whomITalkTo[j] = 1;
								departmentArray[i]->custWaitingForSalesLock->Release();
								printf("Customer [%d] is asking for assistance from DepartmentSalesman [%d].\n", id, j);
								debugPrint("A2");
								departmentArray[i]->listOfSalesman[j]->salesmanCV->Signal(departmentArray[i]->listOfSalesman[j]->salesmanLock);
								debugPrint("B2");
								departmentArray[i]->salesStatusArray[j] = 0;
								debugPrint("C2");
								departmentArray[i]->listOfSalesman[j]->salesmanLock->Release();
								departmentArray[i]->custWaitingForRestockCV->Wait(departmentArray[i]->departmentRestockLock);
								debugPrint("D2");
								departmentArray[i]->departmentRestockLock->Release();
								printf("Customer [%d] has received assistance about restocking of [item%d] from DepartmentSalesman [%d].\n", id, i, j);
								break;
							}
							else
							{
								departmentArray[i]->listOfSalesman[j]->salesmanLock->Release();
							}
						}
					}
				}	
			}
			
			//print that the customer has finished in the current department
			if(customerArray[id]->privileged)
				printf("PrivilegedCustomer [%d] has finished shopping in Department[%d]\n", id, i);
			else
				printf("Customer [%d] has finished shopping in Department[%d]\n", id, i);			
		}
	}
	
	bool lookingForCashier = true;
	while(lookingForCashier)
	{
		debugPrint("acquiring cashierlineslock");
		//acquire a lock to look through all of the cashiers' lines
		cashierLinesLock->Acquire();
		debugPrint("has acquired cashierlineslock");
		if(customerArray[id]->privileged) //if the customer is privileged
		{
			//loop through all of the privileged lines and find the shortest one
			
			printf("PrivilegedCustomer [%d] is looking for the Cashier.\n", id);
			
			for(int i = 0; i < NUM_CASHIERS; i++)
			{debugPrint("A %d",i);
				cashierArray[i]->checkOrModifyLinesLock->Acquire();
				if(i == 0)
					customerArray[id]->cashierID = 0;
				else if((cashierArray[i]->cashierPrivilegedLineCount + cashierArray[i]->servingCustomer
						< cashierArray[customerArray[id]->cashierID]->cashierPrivilegedLineCount + cashierArray[customerArray[id]->cashierID]->servingCustomer
						&& !cashierArray[i]->onBreak && !cashierArray[i]->goOnBreak)
						|| ((cashierArray[customerArray[id]->cashierID]->onBreak||cashierArray[customerArray[id]->cashierID]->goOnBreak) && !cashierArray[i]->onBreak && !cashierArray[i]->goOnBreak))
					customerArray[id]->cashierID = i;
				cashierArray[i]->checkOrModifyLinesLock->Release();
			}
			cashierArray[customerArray[id]->cashierID]->cashierPrivilegedLineLock->Acquire();	
			debugPrint("-A- releasing cashierlineslock");
			cashierLinesLock->Release();
			debugPrint("-A- released cashierlineslock");
			cashierArray[customerArray[id]->cashierID]->checkOrModifyLinesLock->Acquire();
			printf("PrivilegedCustomer [%d] chose Cashier [%d] with line of length [%d].\n", id, customerArray[id]->cashierID,
					(cashierArray[customerArray[id]->cashierID]->cashierPrivilegedLineCount + cashierArray[customerArray[id]->cashierID]->servingCustomer));
			if (cashierArray[customerArray[id]->cashierID]->cashierPrivilegedLineCount + cashierArray[customerArray[id]->cashierID]->servingCustomer >0)
			{
				cashierArray[customerArray[id]->cashierID]->cashierPrivilegedLineCount++;
				cashierArray[customerArray[id]->cashierID]->checkOrModifyLinesLock->Release();
				debugPrint("GOING TO SLEEP, privCUSTOMER: %d", id);
				cashierArray[customerArray[id]->cashierID]->cashierPrivilegedLineCV->Wait(cashierArray[customerArray[id]->cashierID]->cashierPrivilegedLineLock);
				debugPrint("CASHIER WOKE ME UP, privCUSTOMER: %d", id);
				cashierArray[customerArray[id]->cashierID]->cashierLock->Acquire();
				cashierArray[customerArray[id]->cashierID]->checkOrModifyLinesLock->Acquire();
				if(!cashierArray[customerArray[id]->cashierID]->onBreak && !cashierArray[customerArray[id]->cashierID]->goOnBreak)
				{
					//cashierArray[customerArray[id]->cashierID]->cashierLock->Acquire();
					//cashierArray[customerArray[id]->cashierID]->cashierPrivilegedLineCount++;
					lookingForCashier = false;
					cashierArray[customerArray[id]->cashierID]->servingCustomer = 1;
					cashierArray[customerArray[id]->cashierID]->customerID = id; //give trolly (customer id) to cashier
					cashierArray[customerArray[id]->cashierID]->cashierPrivilegedLineCount--;
					cashierArray[customerArray[id]->cashierID]->checkOrModifyLinesLock->Release();
				}
				else
				{
					debugPrint("this cashier (%d) is going on break, need to find a new one.",customerArray[id]->cashierID);
					cashierArray[customerArray[id]->cashierID]->checkOrModifyLinesLock->Release();
					cashierArray[customerArray[id]->cashierID]->cashierLock->Release();
				}
				cashierArray[customerArray[id]->cashierID]->cashierPrivilegedLineLock->Release();
				debugPrint("CASHIER WOKE ME UP, privCUSTOMER: %d", id);
			}
			else if(!cashierArray[customerArray[id]->cashierID]->onBreak && !cashierArray[customerArray[id]->cashierID]->goOnBreak)
			{
				cashierArray[customerArray[id]->cashierID]->servingCustomer = 1;
				//lookingForCashier = false;
				//cashierArray[customerArray[id]->cashierID]->cashierPrivilegedLineCount++;
				cashierArray[customerArray[id]->cashierID]->checkOrModifyLinesLock->Release();
				debugPrint("ABOUT TO ACQUIRE, privCUSTOMER: %d", id);
				cashierArray[customerArray[id]->cashierID]->cashierLock->Acquire();
				cashierArray[customerArray[id]->cashierID]->checkOrModifyLinesLock->Acquire();
				if (!cashierArray[customerArray[id]->cashierID]->onBreak && !cashierArray[customerArray[id]->cashierID]->goOnBreak)
				{
					lookingForCashier = false;
					//cashierArray[customerArray[id]->cashierID]->cashierPrivilegedLineCount++;
					cashierArray[customerArray[id]->cashierID]->servingCustomer = 1;
					cashierArray[customerArray[id]->cashierID]->customerID = id; //give trolly (customer id) to cashier
					//cashierArray[customerArray[id]->cashierID]->cashierPrivilegedLineCount--;
					cashierArray[customerArray[id]->cashierID]->checkOrModifyLinesLock->Release();
				}
				else
				{
					cashierArray[customerArray[id]->cashierID]->servingCustomer = 0;
					debugPrint("this cashier (%d) is going on break, need to find a new one.",customerArray[id]->cashierID);
					cashierArray[customerArray[id]->cashierID]->checkOrModifyLinesLock->Release();
					cashierArray[customerArray[id]->cashierID]->cashierLock->Release();
				}
				debugPrint("releasing cashierprivLINElock");
				cashierArray[customerArray[id]->cashierID]->cashierPrivilegedLineLock->Release();
				debugPrint("released cashierprivLINElock");
				//cashierArray[customerArray[id]->cashierID]->cashierCV->Signal(cashierArray[customerArray[id]->cashierID]->cashierLock);
			}
			else
			{
				cashierArray[customerArray[id]->cashierID]->checkOrModifyLinesLock->Release();
				debugPrint("releasing cashierprivLINElock");
				cashierArray[customerArray[id]->cashierID]->cashierPrivilegedLineLock->Release();
				debugPrint("released cashierprivLINElock");
			}
			
			/*if(!cashierArray[customerArray[id]->cashierID]->onBreak && !cashierArray[customerArray[id]->cashierID]->goOnBreak)
			{
				cashierArray[customerArray[id]->cashierID]->checkOrModifyLinesLock->Acquire();
				cashierArray[customerArray[id]->cashierID]->servingCustomer = 1;
				cashierArray[customerArray[id]->cashierID]->customerID = id; //give trolly (customer id) to cashier
				cashierArray[customerArray[id]->cashierID]->cashierPrivilegedLineCount--;
				cashierArray[customerArray[id]->cashierID]->checkOrModifyLinesLock->Release();
			}*/
		}
		else //if the customer is not privileged
		{
			//loop through all of the cashier's total line sizes (the sum of a cashier's regular line and privileged line) and find one with the shortest total
			printf("Customer [%d] is looking for the Cashier.\n", id);
			for(int i = 0; i < NUM_CASHIERS; i++)
			{debugPrint("B %d",i);
				cashierArray[i]->checkOrModifyLinesLock->Acquire();
				if(i == 0)
					customerArray[id]->cashierID = 0;
				else if((cashierArray[i]->cashierLineCount + cashierArray[i]->cashierPrivilegedLineCount + cashierArray[i]->servingCustomer
						< cashierArray[customerArray[id]->cashierID]->cashierLineCount + cashierArray[customerArray[id]->cashierID]->cashierPrivilegedLineCount + cashierArray[customerArray[id]->cashierID]->servingCustomer
						&& !cashierArray[i]->onBreak && !cashierArray[i]->goOnBreak)
						|| ((cashierArray[customerArray[id]->cashierID]->onBreak||cashierArray[customerArray[id]->cashierID]->goOnBreak) && !cashierArray[i]->onBreak && !cashierArray[i]->goOnBreak) )
				{
					customerArray[id]->cashierID = i;
				}
				cashierArray[i]->checkOrModifyLinesLock->Release();
			}
			debugPrint("acquiring cashierLINElock");
			cashierArray[customerArray[id]->cashierID]->cashierLineLock->Acquire();
			debugPrint("acquired cashierLINElock");
			debugPrint("-B- releasing cashierlineslock");
			cashierLinesLock->Release();
			debugPrint("-B- released cashierlineslock");
			cashierArray[customerArray[id]->cashierID]->checkOrModifyLinesLock->Acquire();
			printf("Customer [%d] chose Cashier [%d] with line of length [%d].\n", id, customerArray[id]->cashierID,
					(cashierArray[customerArray[id]->cashierID]->cashierLineCount + cashierArray[customerArray[id]->cashierID]->cashierPrivilegedLineCount + cashierArray[customerArray[id]->cashierID]->servingCustomer));
			if ((cashierArray[customerArray[id]->cashierID]->cashierLineCount + cashierArray[customerArray[id]->cashierID]->cashierPrivilegedLineCount + cashierArray[customerArray[id]->cashierID]->servingCustomer)>0)
			{
				cashierArray[customerArray[id]->cashierID]->cashierLineCount++;
				cashierArray[customerArray[id]->cashierID]->checkOrModifyLinesLock->Release();
				debugPrint("waiting on cashierlineCV, cashierLINElock");
				cashierArray[customerArray[id]->cashierID]->cashierLineCV->Wait(cashierArray[customerArray[id]->cashierID]->cashierLineLock);
				debugPrint("woke up from cashierlineCV, cashierLINElock");
				cashierArray[customerArray[id]->cashierID]->cashierLock->Acquire();
				cashierArray[customerArray[id]->cashierID]->checkOrModifyLinesLock->Acquire();
				if(!cashierArray[customerArray[id]->cashierID]->onBreak && !cashierArray[customerArray[id]->cashierID]->goOnBreak)
				{
					//cashierArray[customerArray[id]->cashierID]->cashierLock->Acquire();
					//cashierArray[customerArray[id]->cashierID]->cashierLineCount++;
					lookingForCashier = false;
					cashierArray[customerArray[id]->cashierID]->servingCustomer = 1;
					cashierArray[customerArray[id]->cashierID]->customerID = id; //give trolly (customer id) to cashier
					cashierArray[customerArray[id]->cashierID]->cashierLineCount--;
					cashierArray[customerArray[id]->cashierID]->checkOrModifyLinesLock->Release();
				}
				else
				{
					debugPrint("this cashier (%d) is going on break, need to find a new one.",customerArray[id]->cashierID);
					cashierArray[customerArray[id]->cashierID]->checkOrModifyLinesLock->Release();
					cashierArray[customerArray[id]->cashierID]->cashierLock->Release();
				}
				cashierArray[customerArray[id]->cashierID]->cashierLineLock->Release();				
			}
			else if(!cashierArray[customerArray[id]->cashierID]->onBreak && !cashierArray[customerArray[id]->cashierID]->goOnBreak)
			{
				cashierArray[customerArray[id]->cashierID]->servingCustomer = 1;
				//lookingForCashier = false;
				//cashierArray[customerArray[id]->cashierID]->cashierLineCount++;
				cashierArray[customerArray[id]->cashierID]->checkOrModifyLinesLock->Release();
				debugPrint("ABOUT TO ACQUIRE, CUSTOMER: %d", id);
				cashierArray[customerArray[id]->cashierID]->cashierLock->Acquire();
				cashierArray[customerArray[id]->cashierID]->checkOrModifyLinesLock->Acquire();
				if (!cashierArray[customerArray[id]->cashierID]->onBreak && !cashierArray[customerArray[id]->cashierID]->goOnBreak)
				{
					lookingForCashier = false;
					//cashierArray[customerArray[id]->cashierID]->cashierLineCount++;
					cashierArray[customerArray[id]->cashierID]->servingCustomer = 1;
					cashierArray[customerArray[id]->cashierID]->customerID = id; //give trolly (customer id) to cashier
					//cashierArray[customerArray[id]->cashierID]->cashierLineCount--;
					cashierArray[customerArray[id]->cashierID]->checkOrModifyLinesLock->Release();
				}
				else
				{
					cashierArray[customerArray[id]->cashierID]->servingCustomer = 0;
					debugPrint("this cashier (%d) is going on break, need to find a new one.",customerArray[id]->cashierID);
					cashierArray[customerArray[id]->cashierID]->checkOrModifyLinesLock->Release();
					cashierArray[customerArray[id]->cashierID]->cashierLock->Release();
				}
				debugPrint("releasing cashierLINElock");
				cashierArray[customerArray[id]->cashierID]->cashierLineLock->Release();
				debugPrint("released cashierLINElock");
				//cashierArray[customerArray[id]->cashierID]->cashierCV->Signal(cashierArray[customerArray[id]->cashierID]->cashierLock);
			}
			else
			{
				cashierArray[customerArray[id]->cashierID]->checkOrModifyLinesLock->Release();
				debugPrint("releasing cashierLINElock");
				cashierArray[customerArray[id]->cashierID]->cashierLineLock->Release();
				debugPrint("released cashierLINElock");
			}
			
			/*if(!cashierArray[customerArray[id]->cashierID]->onBreak && !cashierArray[customerArray[id]->cashierID]->goOnBreak)
			{
				cashierArray[customerArray[id]->cashierID]->checkOrModifyLinesLock->Acquire();
				cashierArray[customerArray[id]->cashierID]->servingCustomer = 1;
				cashierArray[customerArray[id]->cashierID]->customerID = id; //give trolly (customer id) to cashier
				cashierArray[customerArray[id]->cashierID]->cashierLineCount--;
				cashierArray[customerArray[id]->cashierID]->checkOrModifyLinesLock->Release();
			}*/
		}
	}
	/*
	debugPrint("acquiring cashierlock");
	cashierArray[customerArray[id]->cashierID]->cashierLock->Acquire();
	debugPrint("acquired cashierlock");
	debugPrint("about to wait on cashierlock 1");
	//cashierArray[customerArray[id]->cashierID]->cashierCV->Wait(cashierArray[customerArray[id]->cashierID]->cashierLock); //wait in line for cashier to call customer forward
	debugPrint("woken up on cashierlock 2");
	*/
	//cashierArray[customerArray[id]->cashierID]->servingCustomer = 1;
	//cashierArray[customerArray[id]->cashierID]->customerID = id; //give trolly (customer id) to cashier
	debugPrint("about to signal on cashierlock 3 - //tell cashier that they have trolly (customer id)");
	cashierArray[customerArray[id]->cashierID]->cashierCV->Signal(cashierArray[customerArray[id]->cashierID]->cashierLock); //tell cashier that they have trolly (customer id)
	
	debugPrint("about to wait on cashierlock 4 - //wait for cashier to ask for money");
	cashierArray[customerArray[id]->cashierID]->cashierCV->Wait(cashierArray[customerArray[id]->cashierID]->cashierLock); //wait for cashier to ask for money
	debugPrint("woken up and about to signal on cashierlock 5 - //tell cashier they have the money (it was included with customer id)");
	cashierArray[customerArray[id]->cashierID]->cashierCV->Signal(cashierArray[customerArray[id]->cashierID]->cashierLock); //tell cashier they have the money (it was included with customer id)
	debugPrint("about to wait on cashierlock 6 - //wait for cashier to say whether customer has enough");
	cashierArray[customerArray[id]->cashierID]->cashierCV->Wait(cashierArray[customerArray[id]->cashierID]->cashierLock); //wait for cashier to say whether customer has enough
	debugPrint("woken up on cashierlock 7 - //if the customer gave the cashier money and the cashier said it was enough");
	if(customerArray[id]->canPay) //if the customer gave the cashier money and the cashier said it was enough
	{
		//print that cusomer paid and is waiting for receipt
		if(customerArray[id]->privileged)
			printf("PrivilegedCustomer [%d] pays [%s] to Cashier [%d] and is now waiting for receipt.\n", id, convertToDollarsAndCents(customerArray[id]->bill), customerArray[id]->cashierID);
		else
			printf("Customer [%d] pays [%s] to Cashier [%d] and is now waiting for receipt.\n", id, convertToDollarsAndCents(customerArray[id]->bill), customerArray[id]->cashierID);
		
			debugPrint("about to signal on cashierlock 8 - //pay cashier");
		cashierArray[customerArray[id]->cashierID]->cashierCV->Signal(cashierArray[customerArray[id]->cashierID]->cashierLock); //request receipt from cashier
		debugPrint("about to wait on cashierCV, cashierlock 9 - //wait for acknowledgement of payment");
		cashierArray[customerArray[id]->cashierID]->cashierCV->Wait(cashierArray[customerArray[id]->cashierID]->cashierLock); //wait for receipt from cashier
			debugPrint("about to signal on cashierlock 8a - //request receipt from cashier");
		cashierArray[customerArray[id]->cashierID]->cashierCV->Signal(cashierArray[customerArray[id]->cashierID]->cashierLock); //request receipt from cashier
		debugPrint("about to wait on cashierCV, cashierlock 9a - //wait for receipt from cashier");
		cashierArray[customerArray[id]->cashierID]->cashierCV->Wait(cashierArray[customerArray[id]->cashierID]->cashierLock); //wait for receipt from cashier
		
		//print leaving message
		if(customerArray[id]->privileged)
		{
			//cashierArray[customerArray[id]->cashierID]->checkOrModifyLinesLock->Acquire();
			printf("PrivilegedCustomer [%d] got receipt from Cashier [%d] and is now leaving.\n", id, customerArray[id]->cashierID);
			remainingCustomers--;
			//cashierArray[customerArray[id]->cashierID]->servingCustomer = 0;
			debugPrint("Remaining Customers: ",remainingCustomers);
			//cashierArray[customerArray[id]->cashierID]->checkOrModifyLinesLock->Release();
		}
		else
		{
			//cashierArray[customerArray[id]->cashierID]->checkOrModifyLinesLock->Acquire();
			printf("Customer [%d] got receipt from Cashier [%d] and is now leaving.\n", id, customerArray[id]->cashierID);
			remainingCustomers--;
			//cashierArray[customerArray[id]->cashierID]->servingCustomer = 0;
			debugPrint("Remaining Customers: ",remainingCustomers);
			//cashierArray[customerArray[id]->cashierID]->checkOrModifyLinesLock->Release();
		}
	}
	else
	{
		//print that customer is waiting to negotiate with manager
		if(customerArray[id]->privileged)
		{
			printf("PrivilegedCustomer [%d] cannot pay [%s]\n", id, convertToDollarsAndCents(customerArray[id]->bill));
			printf("PrivilegedCustomer [%d] is waiting for Manager for negotiations.\n", id);
		}
		else
		{
			printf("Customer [%d] cannot pay [%s]\n", id, convertToDollarsAndCents(customerArray[id]->bill));
			printf("Customer [%d] is waiting for Manager for negotiations.\n", id);
		}
		
		manager->managerLock->Acquire();
		customerArray[id]->readyToNegotiate = 1;
		manager->managerCV->Wait(manager->managerLock); //wait for manager for negotiations

		//customer removes items from cart one at a time until bill <= the money in the customer's wallet
		while(customerArray[id]->bill > customerArray[id]->money)
		{
			if(customerArray[id]->trolly.itemList[0] > 0) //if the customer has item type 0
			{
				//remove 1  of item type 0 from trolly and total bill
				customerArray[id]->trolly.itemList[0]--;
				customerArray[id]->bill -= pricesOfItems[0];
				if(customerArray[id]->privileged)
					printf("PrivilegedCustomer [%d] tells Manager to remove [item%d] from trolly.\n", id, 0);
				else
					printf("Customer [%d] tells Manager to remove [item%d] from trolly.\n", id, 0);
				
				manager->itemToRemove = 0;
				manager->managerCV->Signal(manager->managerLock); //tell manager to remove item
				manager->managerCV->Wait(manager->managerLock); //wait for manager to remove item
			}
			else if(customerArray[id]->trolly.itemList[1] > 0) //if the customer has item type 1
			{
				//remove 1  of item type 1 from trolly and total bill
				customerArray[id]->trolly.itemList[1]--;
				customerArray[id]->bill -= pricesOfItems[1];
				if(customerArray[id]->privileged)
					printf("PrivilegedCustomer [%d] tells Manager to remove [item%d] from trolly.\n", id, 1);
				else
					printf("Customer [%d] tells Manager to remove [item%d] from trolly.\n", id, 1);
					
				manager->itemToRemove = 1;
				manager->managerCV->Signal(manager->managerLock); //tell manager to remove item
				manager->managerCV->Wait(manager->managerLock); //wait for manager to remove item
			}
			else if(customerArray[id]->trolly.itemList[2] > 0) //if the customer has item type 2
			{
				//remove 1  of item type 2 from trolly and total bill
				customerArray[id]->trolly.itemList[2]--;
				customerArray[id]->bill -= pricesOfItems[2];
				if(customerArray[id]->privileged)
					printf("PrivilegedCustomer [%d] tells Manager to remove [item%d] from trolly.\n", id, 2);
				else
					printf("Customer [%d] tells Manager to remove [item%d] from trolly.\n", id, 2);
					
				manager->itemToRemove = 2;
				manager->managerCV->Signal(manager->managerLock); //tell manager to remove item
				manager->managerCV->Wait(manager->managerLock); //wait for manager to remove item
			}
			else if(customerArray[id]->trolly.itemList[3] > 0) //if the customer has item type 3
			{
				//remove 1  of item type 3 from trolly and total bill
				customerArray[id]->trolly.itemList[3]--;
				customerArray[id]->bill -= pricesOfItems[3];
				if(customerArray[id]->privileged)
					printf("PrivilegedCustomer [%d] tells Manager to remove [item%d] from trolly.\n", id, 3);
				else
					printf("Customer [%d] tells Manager to remove [item%d] from trolly.\n", id, 3);
					
				manager->itemToRemove = 3;
				manager->managerCV->Signal(manager->managerLock); //tell manager to remove item
				manager->managerCV->Wait(manager->managerLock); //wait for manager to remove item
			}
			else if(customerArray[id]->trolly.itemList[4] > 0) //if the customer has item type 4
			{
				//remove 1  of item type 4 from trolly and total bill
				customerArray[id]->trolly.itemList[4]--;
				customerArray[id]->bill -= pricesOfItems[4];
				if(customerArray[id]->privileged)
					printf("PrivilegedCustomer [%d] tells Manager to remove [item%d] from trolly.\n", id, 4);
				else
					printf("Customer [%d] tells Manager to remove [item%d] from trolly.\n", id, 4);
					
				manager->itemToRemove = 4;
				manager->managerCV->Signal(manager->managerLock); //tell manager to remove item
				manager->managerCV->Wait(manager->managerLock); //wait for manager to remove item
			}
		}
		
		manager->itemToRemove = -2; //done removing items
		
		//print that the customer has removed items and is waiting for manager to give the receeipt
		if(customerArray[id]->privileged)
			printf("PrivilegedCustomer [%d] pays [%s] to Manager after removing items and is waiting for receipt from Manager.\n", id, convertToDollarsAndCents(customerArray[id]->bill));
		else
			printf("Customer [%d] pays [%s] to Manager after removing items and is waiting for receipt from Manager.\n", id, convertToDollarsAndCents(customerArray[id]->bill));
		
		manager->managerCV->Signal(manager->managerLock); //tell manager you're done removing items and pay
		manager->managerCV->Wait(manager->managerLock); //wait for receipt
		
		//print that customer is leaving
		printf("Customer [%d] got receipt from Manager and is now leaving.\n", id);
		remainingCustomers--;
		//cashierArray[customerArray[id]->cashierID]->servingCustomer = 0;
		debugPrint("Remaining Customers: ",remainingCustomers);
		manager->managerLock->Release();
	}
	//cashierArray[customerArray[id]->cashierID]->servingCustomer = 0;
	debugPrint("releasing cashierlock");
	cashierArray[customerArray[id]->cashierID]->cashierLock->Release();
	//if (remainingCustomers == 0)
	//	printEndOfSimulationOutputs();
	
}
//=================================================//
//---------------(END) CUSTOMER--------------------//
//=================================================//

//=================================================//
//-------------------CASHIER-----------------------//
//=================================================//
void CashierSetup(Cashier *c, int id){ //called when initializing a new Cashier
	c->identifier = id;
	c->cashierLineCount = 0;
	c->cashierPrivilegedLineCount = 0;
	c->customerID = -1;
	c->servingCustomer = 0;
	c->goOnBreak = 0;
	c->onBreak = 0;
	
	c->checkOrModifyLinesLock = new Lock("Check or Modify Lines");
	c->cashierLock = new Lock("Cashier Lock");
	c->cashierCV = new Condition("Cashier CV");
	c->cashierLineLock = new Lock("Cashier Line Lock");
	c->cashierLineCV = new Condition("Cashier Line CV");
	c->cashierPrivilegedLineLock = new Lock("Cashier Privileged Line Lock");
	c->cashierPrivilegedLineCV = new Condition("Cashier Privileged Line CV");
}

void CheckoutCounterSetup(CheckoutCounter *cc, int id){ //called when initializing a new CheckoutCounter
	cc->identifier = id;
	cc->moneyInDrawer = 0;
	cc->totalCounterSales = 0;
	cc->drawerLock = new Lock("Drawer Lock");;
}

void CashierFunction(int id){
	while(true)
	{
		//Get line locks
		debugPrint("Cashier");
		cashierArray[id]->cashierLock->Acquire();
		debugPrint("acquiring cashierlineslock");
		cashierLinesLock->Acquire();
		debugPrint("acquired cashierlineslock");
		
		debugPrint("acquiring cashierpriviligedLINElock");
		cashierArray[id]->cashierPrivilegedLineLock->Acquire();
		debugPrint("privileged cashierLINElock");
		debugPrint("acquiring cashierLINElock");
		cashierArray[id]->cashierLineLock->Acquire();
		debugPrint("acquired cashierLINElock");
		//cashierArray[id]->cashierLock->Acquire();
		debugPrint("has ALL the locks");
		cashierArray[id]->checkOrModifyLinesLock->Acquire();
		if (/*cashierArray[id]->goOnBreak ||*/ cashierArray[id]->onBreak)
		{
			//if (cashierArray[id]->onBreak)
			//{
				printf("Cashier [%d] was called from break by Manager to work.\n", id);
				cashierArray[id]->goOnBreak = 0;
				cashierArray[id]->onBreak = 0;
			//}
		}
		//cashierArray[id]->checkOrModifyLinesLock->Acquire();
		cashierArray[id]->servingCustomer = 0;
		cashierArray[id]->customerID = -1;
		if(cashierArray[id]->cashierPrivilegedLineCount > 0)
		{
			cashierArray[id]->checkOrModifyLinesLock->Release();
			debugPrint("signaling privcustomer, cashierCV, cashierLock");
			//Call up next privileged customer
			debugPrint("signaling cashierprivilegedLINElock");
			cashierArray[id]->cashierPrivilegedLineCV->Signal(cashierArray[id]->cashierPrivilegedLineLock);
			//cashierArray[id]->cashierPrivilegedLineCount--;
		}
		else if(cashierArray[id]->cashierLineCount > 0)
		{
			cashierArray[id]->checkOrModifyLinesLock->Release();
			debugPrint("signaling customer, cashierCV, cashierLock");
			//Call up next regular customer
			
			debugPrint("signaling cashierLINElock");
			cashierArray[id]->cashierLineCV->Signal(cashierArray[id]->cashierLineLock);
			//cashierArray[id]->cashierLineCount--;
		}
		else
		{
			cashierArray[id]->checkOrModifyLinesLock->Release();
			debugPrint("Signaling cashierCV, cashierLock");
			cashierArray[id]->cashierCV->Signal(cashierArray[id]->cashierLock);
		}
		
		
		debugPrint("releasing cashierprivilegedLINElock");
		cashierArray[id]->cashierPrivilegedLineLock->Release();
		debugPrint("released cashierprivilegedLINElock");
		debugPrint("releasing cashierLINElock");
		cashierArray[id]->cashierLineLock->Release();
		debugPrint("released cashierLINElock");
		debugPrint("releasing cashierlineslock");
		cashierLinesLock->Release();
		debugPrint("released cashierlineslock");
		
		//Wait for customer to give trolly (customer ID) to cashier
		debugPrint("waiting on cashierCV, cashierLock");
		cashierArray[id]->cashierCV->Wait(cashierArray[id]->cashierLock);
		cashierArray[id]->checkOrModifyLinesLock->Acquire();
		if(cashierArray[id]->servingCustomer == 1)
		{
			cashierArray[id]->checkOrModifyLinesLock->Release();
			//Add up items in trolly
			int bill = 0;
			for(int i = 0; i < NUM_DEPARTMENTS; i++)
			{
				if(customerArray[cashierArray[id]->customerID]->privileged)
				{
					for(int j = 0; j < customerArray[cashierArray[id]->customerID]->trolly.itemList[i]; j++)
					{
						//print that cashier got item
						printf("Cashier [%d] got [item%d] from trolly of PrivilegedCustomer [%d].\n", id, i, cashierArray[id]->customerID);
					}
				}
				else
				{
					for(int j = 0; j < customerArray[cashierArray[id]->customerID]->trolly.itemList[i]; j++)
					{
						//print that cashier got item
						printf("Cashier [%d] got [item%d] from trolly of Customer [%d].\n", id, i, cashierArray[id]->customerID);
					}
				}
				
				//add items of type i from customer's trolly to customer's bill
				bill += customerArray[cashierArray[id]->customerID]->trolly.itemList[i] * pricesOfItems[i]; 
			}
			
			//Give customer their bill
			cashierArray[id]->cashierLock->Acquire();
			customerArray[cashierArray[id]->customerID]->bill = bill;
			
			// Tell customer that they have the bill
			if(customerArray[cashierArray[id]->customerID]->privileged)
				printf("Cashier [%d] tells PrivilegedCustomer [%d] total cost is $[%s].\n", id, cashierArray[id]->customerID, convertToDollarsAndCents(bill));
			else
				printf("Cashier [%d] tells Customer [%d] total cost is $[%s].\n", id, cashierArray[id]->customerID, convertToDollarsAndCents(bill));
			cashierArray[id]->cashierCV->Signal(cashierArray[id]->cashierLock);
			
			// Wait for customer to pay
			debugPrint("waiting on cashierCV, cashierLock 2");
			cashierArray[id]->cashierCV->Wait(cashierArray[id]->cashierLock);
			
			if(customerArray[cashierArray[id]->customerID]->money < bill) //if the customer can't pay
			{	
				//let the customer know they can't pay
				customerArray[cashierArray[id]->customerID]->canPay = 0;
				
				//tell customer to wait for manager
				if(customerArray[cashierArray[id]->customerID]->privileged)
					printf("Cashier [%d] asks PrivilegedCustomer [%d] to wait for Manager.\n", id, cashierArray[id]->customerID);
				else
					printf("Cashier [%d] asks Customer [%d] to wait for Manager.\n", id, cashierArray[id]->customerID);
				cashierArray[id]->cashierCV->Signal(cashierArray[id]->cashierLock);
				
				//Give manager cashier/counter ID so he can find the problem
				debugPrint("A %d", cashierArray[id]->customerID);
				manager->managerLock->Acquire();
				debugPrint("B %d", cashierArray[id]->customerID);
				while(manager->currentCashierID != id) //while the manager is not helping the customer at this counter
				{
					debugPrint("C");
					if(manager->currentCashierID == -1) //if the manager isn't helping anyone
					{
						debugPrint("D");
						manager->currentCashierID = id; //tell the manager to help the customer at this counter
					}
					else
					{
						debugPrint("E");
						manager->managerCashierLineCV->Wait(manager->managerLock); //wait for manager to say he's done helping the previous customer
						debugPrint("F");
					}
					debugPrint("G");
				}
				debugPrint("H");
				
				//Tells manager that customer does not have enough money
				if(customerArray[cashierArray[id]->customerID]->privileged)
					printf("Cashier [%d] informs the Manager that PrivilegedCustomer [%d] does not have enough money.\n", id, cashierArray[id]->customerID);
				else
					printf("Cashier [%d] informs the Manager that Customer [%d] does not have enough money.\n", id, cashierArray[id]->customerID);
				
				//Waits for manager to finish helping customer and give cashier the final bill (so the cashier can add the money to the drawer)
				debugPrint("manager's current cashier ID %d", manager->currentCashierID);
				cashierArray[id]->cashierLock->Release();
				debugPrint("Cashier waiting on managerCashierHelpCV, managerLock");
				manager->managerCashierHelpCV->Wait(manager->managerLock);
				
				bill = customerArray[cashierArray[id]->customerID]->bill; //customer's final bill
				manager->managerLock->Release();
			}
			else
			{			
				//Take the appropriate amount of money from the customer (give them their change)
				//customerArray[cashierArray[id]->customerID]->money -= bill;
				
				// Tell customer they can leave
				if(customerArray[cashierArray[id]->customerID]->privileged)
				{
					//cashierArray[id]->cashierPrivilegedLineCount--;
					debugPrint("privlinecount %d",cashierArray[id]->cashierPrivilegedLineCount);
					debugPrint("signaling on cashierCV, cashierLock 2a - //tell customer that he had enough money");
					cashierArray[id]->cashierCV->Signal(cashierArray[id]->cashierLock); //tell customer the payment was successful
					debugPrint("waiting on cashierCV, cashierLock 3a - //wait for customer to pay");
					cashierArray[id]->cashierCV->Wait(cashierArray[id]->cashierLock); //wait for customer to ask for receipt
					//Take the appropriate amount of money from the customer (give them their change)
					customerArray[cashierArray[id]->customerID]->money -= bill;
					printf("Cashier [%d] got money $[%s] from PrivilegedCustomer [%d].\n", id, convertToDollarsAndCents(bill), cashierArray[id]->customerID);
					debugPrint("signaling on cashierCV, cashierLock 4a - //tell customer the payment was successful");
					cashierArray[id]->cashierCV->Signal(cashierArray[id]->cashierLock); //tell customer the payment was successful
					debugPrint("waiting on cashierCV, cashierLock 5a - //wait for customer to ask for receipt");
					cashierArray[id]->cashierCV->Wait(cashierArray[id]->cashierLock); //wait for customer to ask for receipt
					printf("Cashier [%d] gave the receipt to PrivilegedCustomer [%d] and tells him to leave.\n", id, cashierArray[id]->customerID);
				}
				else
				{
					//cashierArray[id]->cashierLineCount--;
					debugPrint("linecount %d",cashierArray[id]->cashierLineCount);
					debugPrint("signaling on cashierCV, cashierLock 2b - //tell customer that he had enough money");
					cashierArray[id]->cashierCV->Signal(cashierArray[id]->cashierLock); //tell customer the payment was successful
					debugPrint("waiting on cashierCV, cashierLock 3b - //wait for customer to pay");
					cashierArray[id]->cashierCV->Wait(cashierArray[id]->cashierLock); //wait for customer to ask for receipt
					//Take the appropriate amount of money from the customer (give them their change)
					customerArray[cashierArray[id]->customerID]->money -= bill;
					printf("Cashier [%d] got money $[%s] from Customer [%d].\n", id, convertToDollarsAndCents(bill), cashierArray[id]->customerID);
					debugPrint("signaling on cashierCV, cashierLock 4b - //tell customer the payment was successful");
					cashierArray[id]->cashierCV->Signal(cashierArray[id]->cashierLock); //tell customer the payment was successful
					debugPrint("waiting on cashierCV, cashierLock 5b - //wait for customer to ask for receipt");
					cashierArray[id]->cashierCV->Wait(cashierArray[id]->cashierLock); //wait for customer to ask for receipt
					printf("Cashier [%d] gave the receipt to Customer [%d] and tells him to leave.\n", id, cashierArray[id]->customerID);
					/*debugPrint("linecount %d",cashierArray[id]->cashierLineCount);
					printf("Cashier [%d] got money $[%s] from Customer [%d].\n", id, convertToDollarsAndCents(bill), cashierArray[id]->customerID);
					debugPrint("signaling on cashierCV, cashierLock 4 - //tell customer the payment was successful");
					cashierArray[id]->cashierCV->Signal(cashierArray[id]->cashierLock); //tell customer the payment was successful
					debugPrint("waiting on cashierCV, cashierLock 5 - //wait for customer to ask for receipt");
					cashierArray[id]->cashierCV->Wait(cashierArray[id]->cashierLock); //wait for customer to ask for receipt
					printf("Cashier [%d] gave the receipt to Customer [%d] and tells him to leave.\n", id, cashierArray[id]->customerID);*/
				}
				
				debugPrint("privlinecount %d",cashierArray[id]->cashierPrivilegedLineCount);
				debugPrint("linecount %d",cashierArray[id]->cashierLineCount);
				
				debugPrint("signaling on cashierCV, cashierLock 6 - //tell customer to leave");
				cashierArray[id]->cashierCV->Signal(cashierArray[id]->cashierLock);
			}
			
			//Add the customer's money to drawer
			checkoutCounterArray[id]->drawerLock->Acquire();
			checkoutCounterArray[id]->moneyInDrawer += bill;
			checkoutCounterArray[id]->totalCounterSales += bill;
			checkoutCounterArray[id]->drawerLock->Release();
			
			//put back trolly
			trollyLineLock->Acquire();
			numTrolly++;
			trollyLineCV->Signal(trollyLineLock);
			trollyLineLock->Release();
		}
		else
		{
			cashierArray[id]->checkOrModifyLinesLock->Release();
		}
		if(cashierArray[id]->goOnBreak)
		{
			cashierArray[id]->onBreak = 1;
			
			cashierArray[id]->cashierPrivilegedLineLock->Acquire();
			cashierArray[id]->cashierLineLock->Acquire();
			cashierArray[id]->checkOrModifyLinesLock->Acquire();
			debugPrint("going on break, broadcast to lines");
			cashierArray[id]->cashierPrivilegedLineCV->Broadcast(cashierArray[id]->cashierPrivilegedLineLock);
			cashierArray[id]->cashierPrivilegedLineCount = 0;
			cashierArray[id]->cashierLineCV->Broadcast(cashierArray[id]->cashierLineLock);
			cashierArray[id]->cashierLineCount = 0;
			
			cashierArray[id]->cashierPrivilegedLineLock->Release();
			cashierArray[id]->cashierLineLock->Release();
			cashierArray[id]->checkOrModifyLinesLock->Release();
			
			//Go on break until signaled by manager
			printf("Cashier [%d] is going on break.\n", id);
			debugPrint("waiting on cashierCV, cashierLock 4");
			cashierArray[id]->cashierCV->Wait(cashierArray[id]->cashierLock);
			
			//Return from break
			//printf("Cashier [%d] was called from break by Manager to work.\n", id);
			//cashierArray[id]->goOnBreak = 0;
			//cashierArray[id]->onBreak = 0;
		}
		debugPrint("releasing cashierlock");
		cashierArray[id]->cashierLock->Release();
		debugPrint("released cashierlock");
	}
}
//=================================================//
//----------------(END) CASHIER--------------------//
//=================================================//


//=================================================//
//----------------GOODS LOADER---------------------//
//=================================================//
//Setup function for the goodsloader: initializes variables in goodsloader
void GoodsLoaderSetup(GoodsLoader *g, int id){
	g->identifier = id;
	//printf("This is goodsloader %d\n", g->identifier);
	
	//initializes the lock for talking to the goodsloader
	/*char *goodsLoaderLockName = (char *)malloc(64 * sizeof(char*));
	sprintf(goodsLoaderLockName, "GoodsLoader [%d] Lock", id);
	g->goodsLoaderLock = new Lock(goodsLoaderLockName);*/
	
	//initializes the condition variable for talking to the goodsloader
	char *goodsLoaderCVName = (char *)malloc(64 * sizeof(char*));
	sprintf(goodsLoaderCVName, "GoodsLoader [%d] CV", id);
	g->goodsLoaderCV = new Condition(goodsLoaderCVName);
}

/*This function is called when a salesman is complaining about an out of stock item.
	Wakes up a goods loader by checking the goodsLoaderStatus array
	printf("GoodsLoader [%d] is informed by DepartmentSalesman [%d] of Department [%d] to restock [item%d].\n", goodsLoaderID, salesmanID, departmentID, itemID);
	tell the goodsloader to go restock, resume tasks.
*/
/*void GoodsLoaderComplainingSalesman(int goodsID, int departID, int salesID)
{
	int goodsLoaderID, departmentID, salesmanID, itemID;
	goodsLoaderID = goodsID;
	departmentID = departID;
	itemID = departID;
	salesmanID = salesID;
	printf("GoodsLoader [%d] is informed by DepartmentSalesman [%d] of Department [%d] to restock [item%d].\n", goodsLoaderID, salesmanID, departmentID, itemID);
	goodsLoaderArray[goodsLoaderID]->departmentToRestock = departmentID;
	goodsLoaderArray[goodsLoaderID]->itemToRestock = itemID;
	goodsLoaderArray[goodsLoaderID]->salesmanToNotifyAfterRestock = salesmanID;
}*/
void GoodsLoaderFunction(int goodsLoaderID){
	//All goods loader code goes here
	while (true)
	{
			debugPrint("0 - about to acquire SLRL, status: %d",goodsLoaderStatus[goodsLoaderID]);
		//acquire salesloaderrestock lock and CV, and sleep.
		salesLoaderRestockLock->Acquire();
		debugPrint("acquired SLRL");
		//Idle/do nothing
		
			debugPrint("1 status: %d",goodsLoaderStatus[goodsLoaderID]);
		if (goodsLoaderStatus[goodsLoaderID] == 0 || goodsLoaderStatus[goodsLoaderID] == 6)
		{
			for(int i = 0; i < NUM_DEPARTMENTS; i++)
			{
				if (departmentsToRestock[i] != -1)
				{
					goodsLoaderArray[goodsLoaderID]->departmentToRestock = -1;
					goodsLoaderArray[goodsLoaderID]->itemToRestock = -1;
					goodsLoaderArray[goodsLoaderID]->salesmanToNotifyAfterRestock = -1;
					whichDepartmentToRestock[goodsLoaderID] = i;
					salesmanOrderedRestock[goodsLoaderID] = departmentsToRestock[i];
					goodsLoaderStatus[goodsLoaderID] = 1;
					debugPrint("\n\n\n\n\n\n****SECONDARY GOODSLOADER CALL USED*******\n\n\n\n\n");
					printf("DepartmentSalesman [%d] informs the GoodsLoader [%d] that [item%d] is out of stock.\n", salesmanOrderedRestock[goodsLoaderID], goodsLoaderID, whichDepartmentToRestock[goodsLoaderID]);
					departmentsToRestock[i] = -1;
					break;
				}
			}
			if(goodsLoaderStatus[goodsLoaderID] != 1)
			{
				goodsLoaderStatus[goodsLoaderID] = 0;
				debugPrint("2 status: %d",goodsLoaderStatus[goodsLoaderID]);
				printf("GoodsLoader [%d] is waiting for orders to restock.\n", goodsLoaderID);
				goodsLoaderArray[goodsLoaderID]->departmentToRestock = -1;
				goodsLoaderArray[goodsLoaderID]->itemToRestock = -1;
				goodsLoaderArray[goodsLoaderID]->salesmanToNotifyAfterRestock = -1;
				debugPrint("about to wait on goodsLoaderCV, salesLoaderRestockLock");
				goodsLoaderArray[goodsLoaderID]->goodsLoaderCV->Wait(salesLoaderRestockLock);
				debugPrint("woke up from goodsLoaderCV, salesLoaderRestockLock");
			}
		}
		//salesLoaderRestockLock->Release();
		if (goodsLoaderStatus[goodsLoaderID] != 0)
		{
			debugPrint("3 status: %d",goodsLoaderStatus[goodsLoaderID]);
			//GoodsLoader is told by a salesman to restock an item in a department.
			if (goodsLoaderArray[goodsLoaderID]->salesmanToNotifyAfterRestock == -1 && goodsLoaderStatus[goodsLoaderID] == 1)
			{
				goodsLoaderArray[goodsLoaderID]->departmentToRestock = whichDepartmentToRestock[goodsLoaderID];
				goodsLoaderArray[goodsLoaderID]->itemToRestock = whichDepartmentToRestock[goodsLoaderID];
				goodsLoaderArray[goodsLoaderID]->salesmanToNotifyAfterRestock = salesmanOrderedRestock[goodsLoaderID];
				printf("GoodsLoader [%d] is informed by DepartmentSalesman [%d] of Department [%d] to restock [item%d].\n", goodsLoaderID, goodsLoaderArray[goodsLoaderID]->salesmanToNotifyAfterRestock, goodsLoaderArray[goodsLoaderID]->departmentToRestock, goodsLoaderArray[goodsLoaderID]->itemToRestock);
			}debugPrint("1aa");
			if (goodsLoaderStatus[goodsLoaderID] == 1)
			{debugPrint("1a");
				//GoodsLoader attempts to acquire lock for StockRoom, as only one GoodsLoader may be in the StockRoom at a time.
				stockRoomLock->Acquire();
				//If there is already a GoodsLoader in the StockRoom, wait for that GoodsLoader to leave.
				if (goodsLoaderInStockRoom != -1)
					printf("GoodsLoader [%d] is waiting for GoodsLoader [%d] to leave the StockRoom.\n", goodsLoaderID,goodsLoaderInStockRoom);
				else
				{
					goodsLoaderStatus[goodsLoaderID]=2;
					goodsLoaderInStockRoom=goodsLoaderID;
				}
				stockRoomLock->Release();
			}debugPrint("1c");
			
			//Once GoodsLoader acquires lock for StockRoom, the GoodsLoader retrieves 10 of the requested item.
			if (goodsLoaderStatus[goodsLoaderID] == 2)
			{
				//Once GoodsLoader acquires lock for StockRoom, the GoodsLoader retrieves 10 of the requested item.
				goodsLoaderArray[goodsLoaderID]->numberOfItems=10;
				printf("GoodsLoader [%d] is in the StockRoom and got [item%d].\n", goodsLoaderID, goodsLoaderArray[goodsLoaderID]->itemToRestock);
				
				stockRoomLock->Acquire();
				//GoodsLoader leaves the StockRoom and releases its lock.
				goodsLoaderStatus[goodsLoaderID]=3;
				goodsLoaderInStockRoom=-1;
				printf("GoodsLoader [%d] leaves StockRoom.\n", goodsLoaderID);
				stockRoomLock->Release();
			}debugPrint("2c");
			//GoodsLoader walks to the department that needs restocking (this takes time, which is simulated by a random number [between 20 and 40] of 'currentThread->Yield()' statements.
			if (goodsLoaderStatus[goodsLoaderID] == 3)
			{
				int timeToWalkToDepartment = randInt(20,40);
				for (int walkToDepartmentProgress=0; walkToDepartmentProgress < timeToWalkToDepartment; walkToDepartmentProgress++)
					currentThread->Yield();
				goodsLoaderStatus[goodsLoaderID] = 4;
			}debugPrint("3c");
			//GoodsLoader attempts to acquire lock of the department that needs restocking.
			if (goodsLoaderStatus[goodsLoaderID] == 4)
			{
				departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->shelfLock->Acquire();
				//Once the GoodsLoader has the lock of the department that needs restocking, the GoodsLoader restocks the items in that department. 
				departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->numberOfItems += goodsLoaderArray[goodsLoaderID]->numberOfItems;
				goodsLoaderArray[goodsLoaderID]->numberOfItems = 0;
				printf("GoodsLoader [%d] has restocked [item%d] in Department [%d].\n", goodsLoaderID, goodsLoaderArray[goodsLoaderID]->itemToRestock, goodsLoaderArray[goodsLoaderID]->departmentToRestock);
				//GoodsLoader releases the lock of the department that needed restocking.
				departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->shelfLock->Release();
				goodsLoaderStatus[goodsLoaderID] = 5;
			}debugPrint("4c");
			debugPrint("attempting to talk to salesman");
			//GoodsLoader attempts to acquire the lock to talk to the salesman to notify the salesman that restocking is complete.
			departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->goodsLoaderWaitingForSalesLock->Acquire();
			debugPrint("about to release salesLoaderRestockLock");
			salesLoaderRestockLock->Release();
			debugPrint("relased salesLoaderRestockLock, got the line lock for salesman(did we?)");
			//Once GoodsLoader acquires that lock, GoodsLoader notifies the salesman that restocking is complete.
			bool waitInLine = 1;
			//departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->goodsLoaderWaitingLineCount++;
			//	debugPrint("brings goodsLoaderWaitingLineCount up to %d and waits on goodsloaderwaitingforsalesCV, goodsloaderwaitingforsaleslock",departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->goodsLoaderWaitingLineCount);
			//	debugPrint("(salesman status is %d)",departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->salesStatusArray[0]);
			//	departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->goodsLoaderWaitingForSalesCV->Wait(departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->goodsLoaderWaitingForSalesLock);
			//	debugPrint("woke up from goodsLoaderwaitingforsalesCV, goodsLoaderwaitingforsaleslock");
			for (int j = 0; j < NUM_SALESMAN; j++){
				debugPrint("ACQUIRING SALESMAN LOCK");
				departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->listOfSalesman[j]->salesmanLock->Acquire();
				debugPrint("ACQUIRED SALESMAN LOCK");
				debugPrint("goods loader checking salesman status: %d", departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->salesStatusArray[j]);
				if(departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->salesStatusArray[j] == 0 && departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->goodsLoaderWaitingLineCount == 0 && departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->listOfSalesman[j]->goOnBreak == 0 && departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->whomITalkTo[j]==-1)
				{debugPrint("did not have to wait in line");
					waitInLine = 0;
					
					//debugPrint("ACQUIRING SALESMAN LOCK");
					//departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->listOfSalesman[j]->salesmanLock->Acquire();
					//debugPrint("ACQUIRED SALESMAN LOCK");
				
					departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->salesStatusArray[j] = 1;
					departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->salesLoaderIdentifier[j] = goodsLoaderID;
					departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->whomITalkTo[j] = 2;
					departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->goodsLoaderWaitingForSalesLock->Release();
					departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->listOfSalesman[j]->salesmanCV->Signal(departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->listOfSalesman[j]->salesmanLock);
					debugPrint("GOING TO SLEEP");
					departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->listOfSalesman[j]->salesmanCV->Wait(departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->listOfSalesman[j]->salesmanLock);
					debugPrint("WAKING UP");
					departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->listOfSalesman[j]->salesmanCV->Signal(departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->listOfSalesman[j]->salesmanLock);
					departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->listOfSalesman[j]->salesmanLock->Release();
					goodsLoaderStatus[goodsLoaderID] = 6;
					break;
				}
				else 
				{
					debugPrint("nope, salesman %d status: %d",j,departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->salesStatusArray[j]);
					debugPrint("and, salesman %d whomITalkTo: %d",j,departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->whomITalkTo[j]);
					departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->listOfSalesman[j]->salesmanLock->Release();
				}
			}
			if(waitInLine)
			{debugPrint("is waiting in line");
				for (int j = 0; j < NUM_SALESMAN; j++)
				{
					departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->listOfSalesman[j]->salesmanLock->Acquire();
				}
				departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->goodsLoaderWaitingLineCount++;
				debugPrint("brings goodsLoaderWaitingLineCount up to %d and waits on goodsloaderwaitingforsalesCV, goodsloaderwaitingforsaleslock",departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->goodsLoaderWaitingLineCount);
				//debugPrint("(salesman status is %d)",departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->salesStatusArray[0]);
				for (int j = 0; j < NUM_SALESMAN; j++)
				{
					departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->listOfSalesman[j]->salesmanLock->Release();
				}
				departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->goodsLoaderWaitingForSalesCV->Wait(departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->goodsLoaderWaitingForSalesLock);
				debugPrint("woke up from goodsLoaderwaitingforsalesCV, goodsLoaderwaitingforsaleslock");
				for (int j = 0; j < NUM_SALESMAN; j++){
					departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->listOfSalesman[j]->salesmanLock->Acquire();
					debugPrint("(salesman status is %d)",departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->salesStatusArray[0]);
					if(departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->salesStatusArray[j] == 3 && departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->listOfSalesman[j]->goOnBreak == 0 && departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->whomITalkTo[j]==-1)
					{debugPrint("is talking to salesman");
						//departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->listOfSalesman[j]->salesmanLock->Acquire();
						
						departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->salesStatusArray[j] = 1;
						departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->salesLoaderIdentifier[j] = goodsLoaderID;
						departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->whomITalkTo[j] = 2;

						departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->goodsLoaderWaitingForSalesLock->Release();
						departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->listOfSalesman[j]->salesmanCV->Signal(departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->listOfSalesman[j]->salesmanLock);
						departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->listOfSalesman[j]->salesmanCV->Wait(departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->listOfSalesman[j]->salesmanLock);
						departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->listOfSalesman[j]->salesmanCV->Signal(departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->listOfSalesman[j]->salesmanLock);
						departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->listOfSalesman[j]->salesmanLock->Release();
						goodsLoaderStatus[goodsLoaderID] = 6;
						break;
					}
					else
					{
						debugPrint("nope, salesman %d status: %d",j,departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->salesStatusArray[j]);
						debugPrint("and, salesman %d whomITalkTo: %d",j,departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->whomITalkTo[j]);
						departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->listOfSalesman[j]->salesmanLock->Release();
					}
				}
			}
			/*departmentArray[goodsLoaderArray[goodsLoaderID]->departmentToRestock]->listOfSalesman[goodsLoaderArray[goodsLoaderID]->salesmanToNotifyAfterRestock]->*/
			/*SalesmanLoaderRestock(goodsLoaderArray[goodsLoaderID]->departmentToRestock, goodsLoaderArray[goodsLoaderID]->salesmanToNotifyAfterRestock, goodsLoaderID);*/
			//GoodsLoader returns to idle OR checks other departments to see if they are out of stock and restocks them? (might cause trouble if another GoodsLoader is already doing so)
		}//end else (if not idle)
	}//end while (true)
	
}
//=================================================//
//--------------(END) GOODS LOADER-----------------//
//=================================================//

//=================================================//
//-------------------SALESMAN----------------------//
//=================================================//
//Setup function for the salesman: initializes variables in salesman
void SalesmanSetup(Salesman *s, int id, int departmentNum){
	s->identifier = id;
	s->departmentNumber = departmentNum;
	s->goOnBreak = 0;
	//printf("This is salesman %d\n", s->identifier);
	//printf("from department %d\n\n", s->departmentNumber);
	
	//initializes the lock for talking to the salesman
	char *salesLockName = (char *)malloc(64 * sizeof(char*));
	sprintf(salesLockName, "Department [%d] Salesman [%d] Lock", s->departmentNumber, id);
	s->salesmanLock = new Lock(salesLockName);
	
	//initializes the condition variable for talking to the salesman
	char *salesCVName = (char *)malloc(64 * sizeof(char*));
	sprintf(salesCVName, "Department [%d] Salesman [%d] CV", s->departmentNumber, id);
	s->salesmanCV = new Condition(salesCVName);
	
	//initializes the condition variable for salesman going on break
	char *salesOnBreakCVName = (char *)malloc(64 * sizeof(char*));
	sprintf(salesOnBreakCVName, "Department [%d] Salesman [%d] Break CV", s->departmentNumber, id);
	s->salesmanOnBreakCV = new Condition(salesOnBreakCVName);
}

/*This function is called when a customer is to be greeted
it signals the customer after printing the output statement
*/
void SalesmanGreetingCustomer(int departID, int salesID, int custID)
{
	int departmentID, salesmanID, customerID;
	departmentID = departID;
	salesmanID = salesID;
	customerID = custID;
	if(customerArray[customerID]->privileged)
	{
		printf("DepartmentSalesman [%d] welcomes PrivilegeCustomer [%d] to Department [%d].\n", salesmanID, customerID, departmentID);
	}
	else
	{
		printf("DepartmentSalesman [%d] welcomes Customer [%d] to Department [%d].\n", salesmanID, customerID, departmentID);
	}
	//signal the customer to wake up and continue shopping.
	departmentArray[departmentID]->listOfSalesman[salesmanID]->salesmanCV->Signal
		(departmentArray[departmentID]->listOfSalesman[salesmanID]->salesmanLock);
	departmentArray[departmentID]->whomITalkTo[salesmanID] = -1;
}

/*This function is called when a customer is complaining about an out of stock item.
	Wakes up a goods loader by checking the goodsLoaderStatus array
	printf("DepartmentSalesman [%d] informs the GoodsLoader [%d] that [item%d] is out of stock.\n", salesmanID, loaderID, departmentID);
	tell the goodsloader to go restock, resume tasks.
*/
void SalesmanComplainingCustomer(int departID, int salesID, int custID)
{
	int departmentID, salesmanID, customerID;
	departmentID = departID;
	salesmanID = salesID;
	customerID = custID;
	if(customerArray[customerID]->privileged)
	{
		printf("DepartmentSalesman [%d] is informed by PrivilegeCustomer [%d] that [item%d] is out of stock.\n", salesmanID, customerID, departmentID);
	}
	else
	{
		printf("DepartmentSalesman [%d] is informed by Customer [%d] that [item%d] is out of stock.\n", salesmanID, customerID, departmentID);
	}
	
	debugPrint("A");
	departmentArray[departmentID]->restockAlreadyRequestedLock->Acquire();
	debugPrint("B");
	if(!departmentArray[departmentID]->restockAlreadyRequested)
	{
		debugPrint("C - about to acquire salesLoaderRestockLock");
		salesLoaderRestockLock->Acquire();
		debugPrint("acquired salesLoaderRestockLock");
		for(int i = 0; i<NUM_GOODS_LOADERS; i++)
		{
			if(goodsLoaderStatus[i] == 0)
			{
				departmentArray[departmentID]->restockAlreadyRequested = 1;
				salesmanOrderedRestock[i] = salesmanID;
				whichDepartmentToRestock[i] = departmentID;
				goodsLoaderStatus[i] = 1;
				
				debugPrint("GoodsLoader0 status: %d",goodsLoaderStatus[i]);
				printf("DepartmentSalesman [%d] informs the GoodsLoader [%d] that [item%d] is out of stock.\n", salesmanID, i, departmentID);
				goodsLoaderArray[i]->goodsLoaderCV->Signal(salesLoaderRestockLock);
				break;
			}
		}
		
		if(departmentArray[departmentID]->restockAlreadyRequested == 0)
		{
			departmentsToRestock[departmentID] = salesmanID;
			departmentArray[departmentID]->restockAlreadyRequested = 1;
		}
		
		debugPrint("about to release SLRL GoodsLoader1 status: %d",goodsLoaderStatus[0]);
		salesLoaderRestockLock->Release();
		debugPrint("released SLRL GoodsLoader2 status: %d",goodsLoaderStatus[0]);
		//departmentArray[departmentID]->salesStatusArray[salesmanID]=0;
	}
	departmentArray[departmentID]->salesStatusArray[salesmanID]=0;
	departmentArray[departmentID]->whomITalkTo[salesmanID] = -1;
	departmentArray[departmentID]->restockAlreadyRequestedLock->Release();
	//departmentArray[departmentID]->whomITalkTo[salesmanID] = -1;
}

/*This function is called when a Goods Loader returns from restocking. 
	The function is informed by the goods loader  that the item is restocked and does a broadcast to everyone waiting on the restock
*/
void SalesmanLoaderRestock(int departID, int salesID, int goodsID)
{
	int departmentID, salesmanID, loaderID;
	departmentID = departID;
	salesmanID = salesID;
	loaderID = goodsID;
	printf("DepartmentSalesman [%d] is informed by the GoodsLoader [%d] that [item%d] is restocked.\n", salesmanID, loaderID, departmentID);
	departmentArray[departmentID]->listOfSalesman[salesmanID]->salesmanCV->Signal
		(departmentArray[departmentID]->listOfSalesman[salesmanID]->salesmanLock);
	printf("DepartmentSalesman [%d] informs the Customers that [item%d] is restocked.\n", salesmanID, departmentID);
	//Tells everyone thats waiting for the item restock that it's ready!
	departmentArray[departmentID]->departmentRestockLock->Acquire();
	departmentArray[departmentID]->custWaitingForRestockCV->Broadcast(departmentArray[departmentID]->departmentRestockLock);
	departmentArray[departmentID]->departmentRestockLock->Release();
	departmentArray[departmentID]->salesStatusArray[salesmanID]=0;
	departmentArray[departmentID]->whomITalkTo[salesmanID] = -1;
	departmentArray[departmentID]->restockAlreadyRequestedLock->Acquire();
	departmentArray[departmentID]->restockAlreadyRequested = 0;
	departmentArray[departmentID]->restockAlreadyRequestedLock->Release();
}

/* The main salesman function that runs when the thread is in the CPU
	This function will:
		1. first attempt to acquire the lock for the line at the sales department counter. 
		2. Check the 'customerWaitingLineCount' monitor variable to check if anyone is in line
			if so, wake up the first guy in the line, decrement the line count, and set status to READY
			if no ones in line, set status to free and continue;+
		3. Acquire my own lock
		4. Release the line lock
		5. Wait for the customer to walk up to me (Sleeps here)
		6. Gets woken up here, use 'whomITalkTo' array to see what type of person we're speaking to
			if '0' - call SalesmanGreetingCustomer();
			if '1' - call SalesmanComplainingCustomer();
			if '2' - call SalesmanLoaderRestock();
		7. If the manager has put me on break, wait on the salesmanOnBreakCV until signaled. 
		8. Release my lock. 
*/
void SalesmanFunction(int id){
	//All salesman code goes here
	int departmentID, salesmanID; //my salesman ID and department ID, used to extract the 2 values
	salesmanID = id / 100; 			//extracts salesman ID using magic number 100
	departmentID = id - (salesmanID*100); //extracts departmentID
	departmentArray[departmentID]->whomITalkTo[salesmanID] = -1;
	while(true)
	{
		departmentArray[departmentID]->goodsLoaderWaitingForSalesLock->Acquire();
		departmentArray[departmentID]->custWaitingForSalesLock->Acquire();
		departmentArray[departmentID]->listOfSalesman[salesmanID]->salesmanLock->Acquire();
		if(departmentArray[departmentID]->goodsLoaderWaitingLineCount > 0)
		{
			departmentArray[departmentID]->salesStatusArray[salesmanID] = 3;
			departmentArray[departmentID]->goodsLoaderWaitingLineCount--;
			debugPrint("Signaling a waiting goodsloader, status %d, whomITalkTo %d",departmentArray[departmentID]->salesStatusArray[salesmanID],departmentArray[departmentID]->whomITalkTo[salesmanID]);
			departmentArray[departmentID]->goodsLoaderWaitingForSalesCV->Signal(departmentArray[departmentID]->goodsLoaderWaitingForSalesLock);
			//departmentArray[departmentID]->goodsLoaderWaitingLineCount--;
		//	departmentArray[departmentID]->listOfSalesman[salesmanID]->salesmanLock->Acquire();
			//departmentArray[departmentID]->salesStatusArray[salesmanID] = 3;
			departmentArray[departmentID]->listOfSalesman[salesmanID]->salesmanLock->Release();
		}	//first acquire the waiting line lock using the department ID we got
		else if(departmentArray[departmentID]->customerWaitingLineCount > 0){ //If there are customers in line
			//signal the first customer in line
			debugPrint("signaling first customer, salesstatus %d",departmentArray[departmentID]->salesStatusArray[salesmanID]);
			departmentArray[departmentID]->custWaitingForSalesCV->Signal
				(departmentArray[departmentID]->custWaitingForSalesLock);
				
			debugPrint("has signaled first customer, salesstatus %d",departmentArray[departmentID]->salesStatusArray[salesmanID]);
			//remove the customer from the line
			departmentArray[departmentID]->customerWaitingLineCount--;
			debugPrint("Decremented customerWaitingLineCount to ",departmentArray[departmentID]->customerWaitingLineCount);
			//sets my status to 3, READY TO SPEAK TO CUSTOMERS
			debugPrint("now ready to speak to customers, salesstatus %d",departmentArray[departmentID]->salesStatusArray[salesmanID]);
		//	departmentArray[departmentID]->listOfSalesman[salesmanID]->salesmanLock->Acquire();
			departmentArray[departmentID]->salesStatusArray[salesmanID] = 3;
			departmentArray[departmentID]->listOfSalesman[salesmanID]->salesmanLock->Release();
		}
		else if (departmentArray[departmentID]->salesStatusArray[salesmanID] != 1 && departmentArray[departmentID]->whomITalkTo[salesmanID] != 1)
		{	
			//else, set my status to FREE
		//	departmentArray[departmentID]->listOfSalesman[salesmanID]->salesmanLock->Acquire();
			debugPrint("not busy and not talking to complaining customer, so setting status to free, salesstatus %d, whomITalkTo %d",departmentArray[departmentID]->salesStatusArray[salesmanID],departmentArray[departmentID]->whomITalkTo[salesmanID]);
			departmentArray[departmentID]->salesStatusArray[salesmanID] = 0;
			debugPrint("salesstatus %d, whomITalkTo %d",departmentArray[departmentID]->salesStatusArray[salesmanID],departmentArray[departmentID]->whomITalkTo[salesmanID]);
			departmentArray[departmentID]->listOfSalesman[salesmanID]->salesmanLock->Release();
		}
		else
		{
			departmentArray[departmentID]->listOfSalesman[salesmanID]->salesmanLock->Release();
		}
		//acquires the salesman's own lock
		
		departmentArray[departmentID]->listOfSalesman[salesmanID]->salesmanLock->Acquire();
		//release the lock for the line
		departmentArray[departmentID]->goodsLoaderWaitingForSalesLock->Release();
		departmentArray[departmentID]->custWaitingForSalesLock->Release();
		//wait for the customer to walk up and talk to me
		debugPrint("salesmanlock, salesstatus %d, whomITalkTo %d",departmentArray[departmentID]->salesStatusArray[salesmanID],departmentArray[departmentID]->whomITalkTo[salesmanID]);
		
		//departmentArray[departmentID]->listOfSalesman[salesmanID]->salesmanCV->Signal(
		//	departmentArray[departmentID]->listOfSalesman[salesmanID]->salesmanLock);
		
		if(departmentArray[departmentID]->salesStatusArray[salesmanID] != 3 || (departmentArray[departmentID]->salesStatusArray[salesmanID] == 3 && departmentArray[departmentID]->whomITalkTo[salesmanID]==-1))
		{
			departmentArray[departmentID]->salesStatusArray[salesmanID] = 0;
		}
		
		if (departmentArray[departmentID]->whomITalkTo[salesmanID]!=1)
		{
			debugPrint("line count %d", departmentArray[departmentID]->customerWaitingLineCount);
			debugPrint("waiting on salesmanlock, salesstatus %d, whomITalkTo %d",departmentArray[departmentID]->salesStatusArray[salesmanID],departmentArray[departmentID]->whomITalkTo[salesmanID]);
			departmentArray[departmentID]->listOfSalesman[salesmanID]->salesmanCV->Signal(
				departmentArray[departmentID]->listOfSalesman[salesmanID]->salesmanLock);
			departmentArray[departmentID]->listOfSalesman[salesmanID]->salesmanCV->Wait(departmentArray[departmentID]->listOfSalesman[salesmanID]->salesmanLock);
		}
		
		debugPrint("woken up, salesstatus %d, whomITalkTo %d",departmentArray[departmentID]->salesStatusArray[salesmanID],departmentArray[departmentID]->whomITalkTo[salesmanID]);
		/*Got woken up here, the customer should have set the whomITalkTo array
		and the salesCustIdentifier/ salesLoaderIdentifier array to pass off the appropriate ID*/
		switch(departmentArray[departmentID]->whomITalkTo[salesmanID])
		{
			//Greeting a customer
			case 0:
				SalesmanGreetingCustomer(departmentID, salesmanID, 
					departmentArray[departmentID]->salesCustIdentifier[salesmanID]);
				break;
			case 1:
				SalesmanComplainingCustomer(departmentID, salesmanID, 
					departmentArray[departmentID]->salesCustIdentifier[salesmanID]);
				break;
			case 2:
				SalesmanLoaderRestock(departmentID, salesmanID, 
					departmentArray[departmentID]->salesLoaderIdentifier[salesmanID]);
				break;
			default:
				debugPrint("switch defaulting, salesstatus %d, whomITalkTo %d",departmentArray[departmentID]->salesStatusArray[salesmanID],departmentArray[departmentID]->whomITalkTo[salesmanID]);
				break;
		}
		debugPrint("after switch, salesstatus %d, whomITalkTo %d",departmentArray[departmentID]->salesStatusArray[salesmanID],departmentArray[departmentID]->whomITalkTo[salesmanID]);
		if(departmentArray[departmentID]->listOfSalesman[salesmanID]->goOnBreak)
		{
			//If we get here, the manager has put me on break;
			departmentArray[departmentID]->salesStatusArray[salesmanID] = 2;
			departmentArray[departmentID]->listOfSalesman[salesmanID]->salesmanOnBreakCV->Wait
				(departmentArray[departmentID]->listOfSalesman[salesmanID]->salesmanLock);
			departmentArray[departmentID]->listOfSalesman[salesmanID]->goOnBreak = 0;
			departmentArray[departmentID]->salesStatusArray[salesmanID] = 0;
		}
		//Release the Lock, task done
		departmentArray[departmentID]->listOfSalesman[salesmanID]->salesmanLock->Release();
	}
}

//DepartmentSetup function, initializes variables in each department
void DepartmentSetup(Department *d, int id){
	d->identifier = id;
	d->numberOfItems = NUM_ITEMS_ON_SHELF;
	d->customerWaitingLineCount = 0;
	d->goodsLoaderWaitingLineCount = 0;
	d->restockAlreadyRequested = 0;
	//initializes the 3 salesmen that wil be working in the department
	for(int j = 0; j < NUM_SALESMAN; j++)
	{
		d->salesStatusArray[j] = 1;
		d->whomITalkTo[j] = -1;
		d->listOfSalesman[j] = (Salesman *)malloc(sizeof(Salesman));
		SalesmanSetup( d->listOfSalesman[j], j, id);
		d->salesCustIdentifier[j] = NULL;
	}

	//initializes the lock for the goods loaders waiting in the sales line
	char *departmentRestockLockName = (char *)malloc(64 * sizeof(char*));
	sprintf(departmentRestockLockName, "Department Restock Lock %d", id);
	d->departmentRestockLock = new Lock(departmentRestockLockName);
	
	//initializes the lock for the goods loaders waiting in the sales line
	char *restockAlreadyRequestedLockName = (char *)malloc(64 * sizeof(char*));
	sprintf(restockAlreadyRequestedLockName, "Restock Already Requested Lock %d", id);
	d->restockAlreadyRequestedLock = new Lock(restockAlreadyRequestedLockName);
	
	//initializes the lock for the goods loaders waiting in the sales line
	char *goodsLineLockName = (char *)malloc(64 * sizeof(char*));
	sprintf(goodsLineLockName, "Goods Loader Sales Department Line Lock %d", id);
	d->goodsLoaderWaitingForSalesLock = new Lock(goodsLineLockName);
	
	//initializes the lock for the customers waiting in the sales line
	char *lineLockName = (char *)malloc(64 * sizeof(char*));
	sprintf(lineLockName, "Sales Department Line Lock %d", id);
	d->custWaitingForSalesLock = new Lock(lineLockName);
	
	//initializes the lock for the customers waiting in the sales line
	char *shelfLock = (char *)malloc(64 * sizeof(char*));
	sprintf(shelfLock, "Sales Department Shelf Lock %d", id);
	d->shelfLock = new Lock(shelfLock);
	
		//initializes the condition variable for goods loaders waiting in the sales line
	char *goodsLineCVName = (char *)malloc(64 * sizeof(char*));
	sprintf(goodsLineCVName, "Goods Loader Sales Department Line CV %d", id);
	d->goodsLoaderWaitingForSalesCV = new Condition(goodsLineCVName);
	
	//initializes the condition variable for customers waiting in the sales line
	char *lineCVName = (char *)malloc(64 * sizeof(char*));
	sprintf(lineCVName, "Sales Department Line CV %d", id);
	d->custWaitingForSalesCV = new Condition(lineCVName);
	
	
	//initializes the condition variable for customers waiting in the sales line
	char *restockCVName = (char *)malloc(64 * sizeof(char*));
	sprintf(restockCVName, "Sales Department restock CV %d", id);
	d->custWaitingForRestockCV = new Condition(restockCVName);
	
	//initializes the condition variable for customers waiting in the sales line
	char *shelfCVName = (char *)malloc(64 * sizeof(char*));
	sprintf(shelfCVName, "Sales Department Shelf CV %d", id);
	d->shelfCV = new Condition(shelfCVName);
}
//=================================================//
//----------------(END) SALESMAN-------------------//
//=================================================//

//=================================================//
//--------------------MANAGER----------------------//
//=================================================//
//Setup function for the manager: initializes variables in manager
void ManagerSetup()
{
	manager->currentCashierID = -1;
	manager->totalSales = 0;
	manager->itemToRemove = -1;
	manager->steps = 0;
	manager->stepsUntilEmptyingDrawers = 100;
	manager->stepsUntilStatingTotalSales = randInt(1,200);
	manager->stepsUntilSendingCashierOnBreak = randInt(1,20);
	manager->stepsUntilSendingSalesmanOnBreak = randInt(1,1000);
	//initializes the lock for talking to the manager
	char *managerLockName = (char *)malloc(64 * sizeof(char*));
	sprintf(managerLockName, "manager Lock");
	manager->managerLock = new Lock(managerLockName);
	
	//initializes the condition variable for talking to the manager
	char *managerCVName = (char *)malloc(64 * sizeof(char*));
	sprintf(managerCVName, "Manager CV");
	manager->managerCV = new Condition(managerCVName);
	
	//initializes the condition variable for interaction between manager/cashiers
	char *managerCashierLineCVName = (char *)malloc(64 * sizeof(char*));
	sprintf(managerCashierLineCVName, "Manager Cashier Line CV");
	manager->managerCashierLineCV = new Condition(managerCashierLineCVName);
	
	//initializes the condition variable for interaction between manager/cashiers
	char *managerCashierHelpCVName = (char *)malloc(64 * sizeof(char*));
	sprintf(managerCashierHelpCVName, "Manager Cashier Help CV");
	manager->managerCashierHelpCV = new Condition(managerCashierHelpCVName);
}
void ManagerEmptyDrawers()
{
	for (int i = 0; i < NUM_CASHIERS; i++)
	{
		checkoutCounterArray[i]->drawerLock->Acquire();
		manager->totalSales += checkoutCounterArray[i]->moneyInDrawer;
		checkoutCounterArray[i]->moneyInDrawer = 0;
		printf("Manager emptied Counter [%d] drawer.\n",i);
		printf("Manager has total sale of $[%s].\n",convertToDollarsAndCents(manager->totalSales));
		checkoutCounterArray[i]->drawerLock->Release();
	}
}
void ManagerSendCashierOnBreak()
{
	bool sentSomeoneOnBreak = false;
	int cashierToSendOnBreak = -1;
	int cashiersOnBreak = 0;
	for (int i = 0; i < NUM_CASHIERS; i++)
	{
		//cashierArray[i]->cashierLock->Acquire();
		if (!sentSomeoneOnBreak && cashierArray[i]->goOnBreak != 1) //&& (cashierArray[i]->cashierLineCount+cashierArray[i]->cashierPrivilegedLineCount)<=1)
		{
			cashierToSendOnBreak = i;
			sentSomeoneOnBreak = true;
		}
		else if (cashierArray[i]->goOnBreak == 1)
		{
			cashiersOnBreak++;
		}
		//cashierArray[i]->cashierLock->Release();
	}
	if (cashiersOnBreak < NUM_CASHIERS-1)
	{
		//cashierArray[cashierToSendOnBreak]->cashierLock->Acquire();
		cashierArray[cashierToSendOnBreak]->checkOrModifyLinesLock->Acquire();
		cashierArray[cashierToSendOnBreak]->goOnBreak = 1;
		//cashierArray[cashierToSendOnBreak]->checkOrModifyLinesLock->Acquire();
		if(cashierArray[cashierToSendOnBreak]->servingCustomer == 0)
		{
			cashierArray[cashierToSendOnBreak]->cashierLock->Acquire();
			cashierArray[cashierToSendOnBreak]->cashierCV->Signal(cashierArray[cashierToSendOnBreak]->cashierLock);
			cashierArray[cashierToSendOnBreak]->cashierLock->Release();
		}
		else 
		{
			debugPrint("servingCustomer, id:",cashierArray[cashierToSendOnBreak]->servingCustomer,cashierArray[cashierToSendOnBreak]->customerID);
		}
		cashierArray[cashierToSendOnBreak]->checkOrModifyLinesLock->Release();
		printf("Manager sends Cashier [%d] on break.\n",cashierToSendOnBreak);
		//cashierArray[cashierToSendOnBreak]->cashierLock->Release();
	}
}
void ManagerSendSalesmanOnBreak()
{
	bool sentSomeoneOnBreak = false;
	int salesmanToSendOnBreak = -1;
	int salesmansOnBreak = 0;
	int department = randInt(0,NUM_DEPARTMENTS-1);
	for (int i = 0; i < NUM_SALESMAN; i++)
	{
		if (!sentSomeoneOnBreak && departmentArray[department]->salesStatusArray[i] != 2)
		{
			salesmanToSendOnBreak = i;
			sentSomeoneOnBreak = true;
		}
		else if (departmentArray[department]->salesStatusArray[i] == 2)
		{
			salesmansOnBreak++;
		}
	}
	if (salesmansOnBreak < NUM_SALESMAN-1)
	{
		departmentArray[department]->listOfSalesman[salesmanToSendOnBreak]->salesmanLock->Acquire();
		departmentArray[department]->salesStatusArray[salesmanToSendOnBreak] = 2;
		printf("Manager sends DepartmentSalesman [%d] of Department [%d] on break.\n",salesmanToSendOnBreak,department);
		departmentArray[department]->listOfSalesman[salesmanToSendOnBreak]->salesmanLock->Release();
	}
}
void ManagerBringSalesmanBackFromBreak()
{
	for (int h = 0; h < NUM_DEPARTMENTS; h++)
	{
		for (int i = 0; i < NUM_SALESMAN; i++)
		{
			departmentArray[h]->listOfSalesman[i]->salesmanLock->Acquire();
			if (departmentArray[h]->salesStatusArray[i] == 2)
			{
				
				departmentArray[h]->listOfSalesman[i]->salesmanOnBreakCV->Signal(departmentArray[h]->listOfSalesman[i]->salesmanLock);
				departmentArray[h]->salesStatusArray[i] = 0;
				printf("Manager brings back DepartmentSalesman [%d] of Department [%d] from break.\n",i,h);
				departmentArray[h]->listOfSalesman[i]->salesmanLock->Release();
			}
			else
			{
				departmentArray[h]->listOfSalesman[i]->salesmanLock->Release();
			}
		}
	}
}
void ManagerBringCashiersBackFromBreak()
{
	for (int i = 0; i < NUM_CASHIERS; i++)
	{
		if (cashierArray[i]->goOnBreak && cashierArray[i]->onBreak)
		{
			cashierArray[i]->cashierLock->Acquire();
			cashierArray[i]->goOnBreak = 0;
			cashierArray[i]->cashierCV->Signal(cashierArray[i]->cashierLock);
			printf("Manager brings back Cashier [%d] from break.\n",i);
			cashierArray[i]->cashierLock->Release();
		}
	}
}
bool ManagerSeesThatCashierLinesAreTooLong()
{
	bool endBreaks = false;
	int cashierToSendOnBreak = -1;
	int cashiersOnBreak = 0;
	for (int i = 0; i < NUM_CASHIERS; i++)
	{
		if ((cashierArray[i]->cashierLineCount+cashierArray[i]->cashierPrivilegedLineCount)>=3)
		{
			endBreaks = true;
		}
	}
	return endBreaks;
}
void ManagerFunction()
{
	//All manager code goes here
	//while(true){currentThread->Yield();	printf("hello\n");	}	
	while (remainingCustomers != 0&& manager->steps<100000)
	{
		manager->steps++;
		//this loop will run between 200 and 1000 times for 10-30 customers
		if (manager->currentCashierID == -1)
		{
			manager->managerLock->Acquire();
			manager->stepsUntilSendingCashierOnBreak--;
			manager->stepsUntilSendingSalesmanOnBreak--;
			manager->stepsUntilEmptyingDrawers--;
			manager->stepsUntilStatingTotalSales--; 
			if (manager->stepsUntilSendingCashierOnBreak <= 0)
			{
				//debugPrint("manager->stepsUntilSendingCashierOnBreak",manager->stepsUntilSendingCashierOnBreak);
				manager->stepsUntilSendingCashierOnBreak = randInt(1,20);
				//debugPrint("manager->stepsUntilSendingCashierOnBreak",manager->stepsUntilSendingCashierOnBreak);
				//if (randInt(1,10)<9)
					ManagerSendCashierOnBreak();
				//else
					//ManagerBringCashiersBackFromBreak();
			}
			if (manager->stepsUntilSendingSalesmanOnBreak <= 0)
			{
				manager->stepsUntilSendingSalesmanOnBreak = randInt(1,1000);
				if (randInt(1,10)<9)
					ManagerSendSalesmanOnBreak();
				else
					ManagerBringSalesmanBackFromBreak();
			}
			if (manager->stepsUntilEmptyingDrawers <= 0)
			{
				manager->stepsUntilEmptyingDrawers = 100;
				ManagerEmptyDrawers();
			}
			if (manager->stepsUntilStatingTotalSales <= 0)
			{
				manager->stepsUntilStatingTotalSales = randInt(1,200);
				printf("-------Total Sale of the entire store until now is $[%s]---------\n",convertToDollarsAndCents(manager->totalSales));
			}
			if (ManagerSeesThatCashierLinesAreTooLong())
				ManagerBringCashiersBackFromBreak();
			
			currentThread->Yield();
			//debugPrint("A");
			manager->managerLock->Release();
			//debugPrint("B");
		}
		else if(customerArray[cashierArray[manager->currentCashierID]->customerID]->readyToNegotiate == 1) //handling a customer who cannot afford items
		{
			debugPrint("acquiring manager lock to help customer");
			manager->managerLock->Acquire();
			debugPrint("acquired manager lock to help customer");
			
			manager->itemToRemove = -1;
			while(manager->itemToRemove != -2)
			{
				if(manager->itemToRemove == -1)
				{
					debugPrint("signaling customer to negotiate");
					manager->managerCV->Signal(manager->managerLock); //tell customer manager is ready to negotiate
				}
				
				debugPrint("waiting for customer to pick next item to remove or pay");
				manager->managerCV->Wait(manager->managerLock); //wait for customer to pick an item to remove or pay if enough items have been removed
				debugPrint("customer to picked next item or paid");
				
				if(manager->itemToRemove != -2)
				{
					//prints that manager removed an item from the customer's trolly
					if(customerArray[cashierArray[manager->currentCashierID]->customerID]->privileged)
						printf("Manager removes [item%d] from the trolly of PrivilegeCustomer [%d].\n", manager->itemToRemove, cashierArray[manager->currentCashierID]->customerID);
					else
						printf("Manager removes [item%d] from the trolly of Customer [%d].\n", manager->itemToRemove, cashierArray[manager->currentCashierID]->customerID);
				
					manager->managerCV->Signal(manager->managerLock); //tell customer item has been removed
				}
			}
						
			//Prints that customer transaction was completed by manager
			if(customerArray[cashierArray[manager->currentCashierID]->customerID]->privileged)
				printf("Manager gave the receipt to PrivilegedCustomer [%d] and tells him to leave.\n", cashierArray[manager->currentCashierID]->customerID);
			else
				printf("Manager gave the receipt to Customer [%d] and tells him to leave.\n", cashierArray[manager->currentCashierID]->customerID);
			
			manager->managerCV->Signal(manager->managerLock); //give receipt to customer and tell him to leave
			
			manager->managerCashierHelpCV->Signal(manager->managerLock); //tell current cashier that transaction has completed
			manager->managerCashierLineCV->Signal(manager->managerLock); //tell next waiting cashier that the manager is now free to help more customers
			manager->currentCashierID = -1;
			manager->managerLock->Release();
		}
		//debugPrint("C");
		//currentThread->Yield();
		//debugPrint("D");
		
		currentThread->Yield();
	}
	if (remainingCustomers==0)
	{
		ManagerEmptyDrawers();
		printEndOfSimulationOutputs();
		debugPrint("Steps: ",manager->steps);
	}
	else
	{
		debugPrint("Timeout! Steps: ",manager->steps);
		debugPrint("RemainingCustomers: ",remainingCustomers);
	}
	
}
//=================================================//
//-----------------(END) MANAGER-------------------//
//=================================================//

//=================================================//
//---------------SETUP FUNCTION--------------------//
//=================================================//
void Setup(int numCashiers, int numLoaders, int numDepartments, int numSalesman, int numCustomers, bool seedBasedOnTime, int customerMoney, int itemsOnShelf){
	stockRoomLock = new Lock("StockRoom Lock");
	trollyLineLock = new Lock("Trolly Line Lock");
	trollyLineCV = new Condition("Trolly Line CV");
	cashierLinesLock = new Lock("Cashier Lines Lock");
	salesLoaderRestockLock = new Lock("Sales Loader Restock Lock");
	NUM_GOODS_LOADERS = numLoaders;
	NUM_MANAGERS = 1;
	NUM_SALESMAN = numSalesman;
	NUM_DEPARTMENTS = numDepartments;
	NUM_TOTAL_CUSTOMERS = numCustomers;
	NUM_CASHIERS = numCashiers;
	NUM_ITEMS_ON_SHELF = itemsOnShelf;
	remainingCustomers = numCustomers;
	
	if(seedBasedOnTime)
		srand(time(NULL)); //generates a seed for rand() based on time
	else
		srand(1); //sets seed for rand() to 1 (useful for getting consistent results when testing)
	
	if(customerMoney == -1)
	{
		//customer brings a minimum of 15 dollars and a
		//maximum of 10 times the price of the most
		//expensive item possible
		CUSTOMER_MONEY = randInt(1500, 1000*MAX_PRICE);
	}
	else
		CUSTOMER_MONEY = customerMoney;
	
	for(int i = 0; i < numDepartments; i++)
	{
		pricesOfItems[i] = randInt(MIN_PRICE*100, MAX_PRICE*100);
		departmentArray[i] = (Department *)malloc(sizeof(Department));
		DepartmentSetup(departmentArray[i], i);
		
		departmentsToRestock[i] = -1;
	}
	
	for(int i = 0; i < numCustomers; i++)
	{
		customerArray[i] = (Customer *)malloc(sizeof(Customer));
		CustomerSetup(customerArray[i], i);
	}
	
	for(int i = 0; i < numCashiers; i++)
	{
		cashierArray[i] = (Cashier *)malloc(sizeof(Cashier));
		CashierSetup(cashierArray[i], i);
		checkoutCounterArray[i] = (CheckoutCounter *)malloc(sizeof(CheckoutCounter));
		CheckoutCounterSetup(checkoutCounterArray[i], i);
	}

	//sets up the goodsloaders and their array.
	for(int i = 0; i < numLoaders; i++) 
	{
		goodsLoaderArray[i] = (GoodsLoader *)malloc(sizeof(GoodsLoader));
		GoodsLoaderSetup(goodsLoaderArray[i], i);
	}
	
	//sets up the manager
	manager = (Manager *)malloc(sizeof(Manager));
	ManagerSetup();
	
	printf("Number of Cashiers = [%d]\n", numCashiers);
	printf("Number of Goods Loaders = [%d]\n", numLoaders);
	printf("Number of PrivilegedCustomers = [%d]\n", NUM_PRIVILEGED_CUSTOMERS);
	printf("Number of Customers = [%d]\n", NUM_CUSTOMERS);
	printf("Number of Managers = [1]\n");
	printf("Number of Departments = [%d]\n", numDepartments);
	printf("Number of DepartmentSalesmen per department = [%d]\n", numSalesman);
	printf("      Items:\n");
	printf("         Number - Price\n");
	for(int i = 0; i < numDepartments; i++)
	{
		printf("            [%d] - $[%s]\n", i, convertToDollarsAndCents(pricesOfItems[i]));
	}
	printf("\n");
	
	//Fork all threads
	for(int i = 0; i < numCustomers; i++)
	{
		char* threadName = (char *)malloc(64 * sizeof(char));
		sprintf(threadName, "Customer [%d]", i);
		Thread *t = new Thread(threadName);
		t->Fork((VoidFunctionPtr)CustomerFunction, i);
	}
	
	for(int i = 0; i<numCashiers; i++)
	{
		char* threadName = (char *)malloc(64 * sizeof(char));
		sprintf(threadName, "Cashier [%d]", i);
		Thread *t = new Thread(threadName);
		t->Fork((VoidFunctionPtr)CashierFunction, i);
	}

	//Spawns salesmen for each department
	for(int i = 0; i < numDepartments; i++)
	{
		//for each department, spawn 3 salesmen
		for(int j = 0; j < numSalesman; j++)
		{
			char* threadName = (char *)malloc(64 * sizeof(char));
			sprintf(threadName, "Salesman [%d] of Department [%d]", j, i);
			Thread *t = new Thread(threadName);
			//Package the 2 values DepartmentID & SalesmanID into 'value'
			int departmentNum, salesmanNum, value;
			departmentNum = i;
			salesmanNum = j;
			value = departmentNum + (salesmanNum * 100);
			//Fork the thread with 'value'
			t->Fork((VoidFunctionPtr)SalesmanFunction, value);
		}
	}
	for(int i = 0; i<numLoaders; i++)
	{
		char* threadName = (char *)malloc(64 * sizeof(char));
		sprintf(threadName, "GoodsLoader [%d]", i);
		Thread *t = new Thread(threadName);
		t->Fork((VoidFunctionPtr)GoodsLoaderFunction, i);
	}
	char* managerThreadName = (char *)malloc(64 * sizeof(char));
	sprintf(managerThreadName, "Manager");
	Thread *mt = new Thread(managerThreadName);
	mt->Fork((VoidFunctionPtr)ManagerFunction,0);
}
//=================================================//
//------------(END) SETUP FUNCTION-----------------//
//=================================================//

//ValidateInput function that takes in the prompt, the error msg 
//and the range of numbers that restricts the amount of each person you may have.
int ValidateInput(char* prompt, char* errorMsg, int min, int max)
{
	int userInput;
	char temp[256];
	while (true)
	{
		printf("%s\n", prompt);
		scanf("%s\n", temp);
		userInput = atoi(temp);
		if (userInput >= min && userInput <= max)
		{
			return userInput;
		}
		else
		{
			printf("%s\n", errorMsg);
		}
	}
}

//Calls ValidateInput to have the users initialize the number of each person to be in the super market simulation
void Test11Initialize()
{	
	NUM_CASHIERS = ValidateInput("Please enter the number of cashiers: \n", "ERROR: The number of cashiers must be between 1-5\n\n", 1, MAX_CASHIERS);
	NUM_GOODS_LOADERS = ValidateInput("Please enter the number of goods loaders: \n", "ERROR: The number of goods loaders must be between 1-5\n\n", 1, MAX_GOODS_LOADERS);
	NUM_DEPARTMENTS = ValidateInput("Please enter the number of departments: \n", "ERROR: The number of departments must be between 1-5\n\n", 1, MAX_DEPARTMENTS);
	NUM_SALESMAN = ValidateInput("Please enter the number of salesman per department: \n", "ERROR: The number of salesman per department must be between 1-3\n", 1, MAX_SALESMAN);
	NUM_TOTAL_CUSTOMERS = ValidateInput("Please enter the number of customers: \n", "ERROR: The number of customers must be between 1-30\n", 1, MAX_CUSTOMERS);
	
	Setup(NUM_CASHIERS, NUM_GOODS_LOADERS, NUM_DEPARTMENTS, NUM_SALESMAN, NUM_TOTAL_CUSTOMERS, true, -1, 10);
}

/************************************************************************************/
/******************************TESTS BELOW THIS LINE*********************************/
/************************************************************************************/
// --------------------------------------------------
// Problem2
// --------------------------------------------------
	void Problem2()
	{
		  Setup(5,5,5,3,30, false, -1, 10);
	}

//=================================================//
//--------------PART 2 TEST SUITES-----------------//
//=================================================//
/*---------------------------------------------------
 TEST1- Test1CustomerAlwaysTakesShortestLine
 This test will prove that customers always take the
 shortest line but no 2 customers ever choose the same
 shortest line at the same time.
---------------------------------------------------*/
void Test1CustomerAlwaysTakesShortestLine()
{
	printf("Executing Test [1].\n\n");
	Setup(5,1,1,3,30, false, -1, 300);
}

/*---------------------------------------------------
 TEST2- Test2ManagerOnlyTalksToOnePerson
Managers can only talk to one Cashier, or one Customer, 
at a time.
----------------------------------------------------*/
void Test2ManagerOnlyTalksToOnePerson()
{
	printf("Executing Test [2].\n\n");
	Setup(5,3,1,3,10, false, 0, 300);
}

/*---------------------------------------------------
 TEST3- Test3CustomerDoesNotLeaveWithoutReceipt
 Customers do not leave until they are given 
 their receipt by the Cashier. The Cashier does not start 
 on another customer until they know that the last 
 Customer has left their area.
----------------------------------------------------*/
void Test3CustomerDoesNotLeaveWithoutReceipt()
{
	printf("Executing Test [3].\n\n");
	Setup(1,1,1,1,2, false, -1, 10);
}

/*---------------------------------------------------
 TEST4- Test4CashierScansTillTrollyEmpty
Cashier scans the items till the trolly is empty.
----------------------------------------------------*/
void Test4CashierScansTillTrollyEmpty()
{
	printf("Executing Test [4].\n\n");
	Setup(1,1,1,1,1, false, -1, 10);
}

/*---------------------------------------------------
 TEST5- Test5CashierSentOnBreakByManager
Cashiers are sent on break by the Manager randomly.
----------------------------------------------------*/
void Test5CashierSentOnBreakByManager()
{
	printf("Executing Test [5].\n\n");
	Setup(5,5,5,3,30, false, -1, 10);
}

/*---------------------------------------------------
 TEST6- Test6ManagerGetsCashiersOffBreak
Managers get Cashiers off their break when lines 
have 3, or more, Customers.
----------------------------------------------------*/
void Test6ManagerGetsCashiersOffBreak()
{
	printf("Executing Test [6]\n\n");
	Setup(5,5,5,3,30, false, -1, 10);
}

/*---------------------------------------------------
 TEST7- Test7TotalSalesNoRaceCondition
Total sales never suffers from a race condition.
----------------------------------------------------*/
void Test7TotalSalesNoRaceCondition()
{
	printf("Executing Test [7].\n\n");
	Setup(5,5,5,3,30, false, -1, 10);
}

/*---------------------------------------------------
 TEST8- Test8GoodsLoaderCustomerShelfAccess
Goods Loader don't try to restock an item on a shelf 
when a Customer is trying to take an item off the shelf.
----------------------------------------------------*/
void Test8GoodsLoaderCustomerShelfAccess()
{
	printf("Executing Test [8].\n\n");
	Setup(1,3,1,3,30, false, -1, 1);
}

/*---------------------------------------------------
 TEST9- Test9OneGoodsLoaderInStockRoom
Only one Goods Loader enters the stock room at a time.
----------------------------------------------------*/
void Test9OneGoodsLoaderInStockRoom()
{
	printf("Executing Test [9].\n\n");
	Setup(5,5,3,3,30, false, -1, 10);
}

/*---------------------------------------------------
 TEST10- Test10CustomerWaitsForItemRestock
Customers wait for items to be restocked 
- when told by the Department Salesman.
----------------------------------------------------*/
void Test10CustomerWaitsForItemRestock()
{
	printf("Executing Test [10].\n\n");
	Setup(5,5,3,3,30, false, -1, 10);
}

/*===================================================
 StartTests function which will display a menu for the 
 super market simulation.
===================================================*/
int StartTests()
{
	//Initialize some variables to use for validating the user input.
	char temp[256];
	int tempInt;
	int userInput;
	int min = 1;
	int max = 10;
	//Prints out the menu
	printf("===========================================\n\n");
	printf("==SUPER MARKET SIMULATION TEST SUITE MENU==\n\n");
	printf("===========================================\n\n");
	printf("[1] Customers always take the shortest line, but no 2 customers ever choose the same shortest line at the same time.\n\n");
	printf("[2] Managers can only talk to one Cashier, or one Customer, at a time.\n\n");
	printf("[3] Customers do not leave until they are given their receipt by the Cashier. The Cashier does not start on another customer until they know that the last Customer has left their area.\n\n");
	printf("[4] Cashier scans the items till the trolly is empty.\n\n");
	printf("[5] Cashiers are sent on break by the Manager randomly.\n\n");
	printf("[6] Managers get Cashiers off their break when lines have 3, or more, Customers.\n\n");
	printf("[7] Total sales never suffers from a race condition.\n\n");
	printf("[8] Goods Loader don't try to restock an item on a shelf when a Customer is trying to take an item off the shelf.\n\n");
	printf("[9] Only one Goods Loader enters the stock room at a time.\n\n");
	printf("[10] Customers wait for items to be restocked - when told by the Department Salesman.\n\n");
	//printf("[11] Simulate the supermarket with a custom number of cashiers, goods loaders, departments, salesmen, and customers.\n     NOTE: For this test, the number of items a customer wants and the price of each item is set randomly.\n\n");
	printf("===========================================\n\n");
	printf("===========END TEST SUITE MENU=============\n\n");
	printf("===========================================\n\n");
	//Enter the input validation loop here
	while (true)
	{
		printf("PLEASE ENTER THE NUMBER OF YOUR CHOICE: \n");
		scanf("%d", &tempInt);
		//cin>>temp;
		userInput=tempInt;
		//userInput = atoi(temp);
		printf("YOU ENTERED [%d].\n\n", userInput);
		if (userInput >= min && userInput <= max)
		{
			//if the input is in the correct range, break out of this loop. 
			break;
		}
		else
		{
			printf("%s\n", "PLEASE ENTER A NUMBER BETWEEN 1-10\n\n");
		}
	}
	//This is a giant if else statement to choose which test to run.
	if(userInput == 1)
	{
		Test1CustomerAlwaysTakesShortestLine();
	}
	else if(userInput == 2)
	{
		Test2ManagerOnlyTalksToOnePerson();
	}
	else if(userInput == 3)
	{
		Test3CustomerDoesNotLeaveWithoutReceipt();
	}
	else if(userInput == 4)
	{
		Test4CashierScansTillTrollyEmpty();
	}
	else if(userInput == 5)
	{
		Test5CashierSentOnBreakByManager();
	}
	else if(userInput == 6)
	{
		Test6ManagerGetsCashiersOffBreak();
	}
	else if(userInput == 7)
	{
		Test7TotalSalesNoRaceCondition();
	}
	else if(userInput == 8)
	{
		Test8GoodsLoaderCustomerShelfAccess();
	}
	else if(userInput == 9)
	{
		Test9OneGoodsLoaderInStockRoom();
	}
	else if(userInput == 10)
	{
		Test10CustomerWaitsForItemRestock();
	}
	/*else if(userInput == 11)
	{
		Test11Initialize();
	}*/

	return 1;
}

//=================================================//
//-----------(END) PART 2 TEST SUITES--------------//
//=================================================//
// --------------------------------------------------
// Test Suite
// --------------------------------------------------


// --------------------------------------------------
// Test 1 - see TestSuite() for details
// --------------------------------------------------
Semaphore t1_s1("t1_s1\n",0);       // To make sure t1_t1 acquires the
                                  // lock before t1_t2
Semaphore t1_s2("t1_s2\n",0);       // To make sure t1_t2 Is waiting on the 
                                  // lock before t1_t3 releases it
Semaphore t1_s3("t1_s3\n",0);       // To make sure t1_t1 does not release the
                                  // lock before t1_t3 tries to acquire it
Semaphore t1_done("t1_done\n",0);   // So that TestSuite knows when Test 1 is
                                  // done
Lock t1_l1("t1_l1\n");		  // the lock tested in Test 1

// --------------------------------------------------
// t1_t1() -- test1 thread 1
//     This is the rightful lock owner
// --------------------------------------------------
void t1_t1() {
    t1_l1.Acquire();
    t1_s1.V();  // Allow t1_t2 to try to Acquire Lock
 
    printf ("%s: Acquired Lock %s, waiting for t3\n\n",currentThread->getName(),
	    t1_l1.getName());
    t1_s3.P();
    printf ("%s: working in CS\n\n",currentThread->getName());
    for (int i = 0; i < 1000000; i++) ;
    printf ("%s: Releasing Lock %s\n\n",currentThread->getName(),
	    t1_l1.getName());
    t1_l1.Release();
    t1_done.V();
}

// --------------------------------------------------
// t1_t2() -- test1 thread 2
//     This thread will wait on the held lock.
// --------------------------------------------------
void t1_t2() {

    t1_s1.P();	// Wait until t1 has the lock
    t1_s2.V();  // Let t3 try to acquire the lock

    printf("%s: trying to acquire lock %s\n\n",currentThread->getName(),
	    t1_l1.getName());
    t1_l1.Acquire();

    printf ("%s: Acquired Lock %s, working in CS\n\n",currentThread->getName(),
	    t1_l1.getName());
    for (int i = 0; i < 10; i++)
	;
    printf ("%s: Releasing Lock %s\n\n",currentThread->getName(),
	    t1_l1.getName());
    t1_l1.Release();
    t1_done.V();
}

// --------------------------------------------------
// t1_t3() -- test1 thread 3
//     This thread will try to release the lock illegally
// --------------------------------------------------
void t1_t3() {

    t1_s2.P();	// Wait until t2 is ready to try to acquire the lock

    t1_s3.V();	// Let t1 do it's stuff
    for ( int i = 0; i < 3; i++ ) {
	printf("%s: Trying to release Lock %s\n\n",currentThread->getName(),
	       t1_l1.getName());
	t1_l1.Release();
    }
}

// --------------------------------------------------
// Test 2 - see TestSuite() for details
// --------------------------------------------------
Lock t2_l1("t2_l1\n");		// For mutual exclusion
Condition t2_c1("t2_c1\n");	// The condition variable to test
Semaphore t2_s1("t2_s1\n",0);	// To ensure the Signal comes before the wait
Semaphore t2_done("t2_done\n",0);     // So that TestSuite knows when Test 2 is
                                  // done

// --------------------------------------------------
// t2_t1() -- test 2 thread 1
//     This thread will signal a variable with nothing waiting
// --------------------------------------------------
void t2_t1() {
    t2_l1.Acquire();
    printf("%s: Lock %s acquired, signalling %s\n\n",currentThread->getName(),
	   t2_l1.getName(), t2_c1.getName());
    t2_c1.Signal(&t2_l1);
    printf("%s: Releasing Lock %s\n\n",currentThread->getName(),
	   t2_l1.getName());
    t2_l1.Release();
    t2_s1.V();	// release t2_t2
    t2_done.V();
}

// --------------------------------------------------
// t2_t2() -- test 2 thread 2
//     This thread will wait on a pre-signalled variable
// --------------------------------------------------
void t2_t2() 
{
    t2_s1.P();	// Wait for t2_t1 to be done with the lock
    t2_l1.Acquire();
    printf("%s: Lock %s acquired, waiting on %s\n\n",currentThread->getName(),
	   t2_l1.getName(), t2_c1.getName());
    t2_c1.Wait(&t2_l1);
    printf("%s: Releasing Lock %s\n\n",currentThread->getName(),
	   t2_l1.getName());
    t2_l1.Release();
}
// --------------------------------------------------
// Test 3 - see TestSuite() for details
// --------------------------------------------------
Lock t3_l1("t3_l1\n");		// For mutual exclusion
Condition t3_c1("t3_c1\n");	// The condition variable to test
Semaphore t3_s1("t3_s1\n",0);	// To ensure the Signal comes before the wait
Semaphore t3_done("t3_done\n",0); // So that TestSuite knows when Test 3 is
                                // done

// --------------------------------------------------
// t3_waiter()
//     These threads will wait on the t3_c1 condition variable.  Only
//     one t3_waiter will be released
// --------------------------------------------------
void t3_waiter() {
    t3_l1.Acquire();
    t3_s1.V();		// Let the signaller know we're ready to wait
    printf("%s: Lock %s acquired, waiting on %s\n\n",currentThread->getName(),
	   t3_l1.getName(), t3_c1.getName());
    t3_c1.Wait(&t3_l1);
    printf("%s: freed from %s\n\n",currentThread->getName(), t3_c1.getName());
    t3_l1.Release();
    t3_done.V();
}


// --------------------------------------------------
// t3_signaller()
//     This threads will signal the t3_c1 condition variable.  Only
//     one t3_signaller will be released
// --------------------------------------------------
void t3_signaller() {

    // Don't signal until someone's waiting
    
    for ( int i = 0; i < 5 ; i++ ) 
	t3_s1.P();
    t3_l1.Acquire();
    printf("%s: Lock %s acquired, signalling %s\n\n",currentThread->getName(),
	   t3_l1.getName(), t3_c1.getName());
    t3_c1.Signal(&t3_l1);
    printf("%s: Releasing %s\n\n",currentThread->getName(), t3_l1.getName());
    t3_l1.Release();
    t3_done.V();
}
 
// --------------------------------------------------
// Test 4 - see TestSuite() for details
// --------------------------------------------------
Lock t4_l1("t4_l1\n");		// For mutual exclusion
Condition t4_c1("t4_c1\n");	// The condition variable to test
Semaphore t4_s1("t4_s1\n",0);	// To ensure the Signal comes before the wait
Semaphore t4_done("t4_done\n",0); // So that TestSuite knows when Test 4 is
                                // done

// --------------------------------------------------
// t4_waiter()
//     These threads will wait on the t4_c1 condition variable.  All
//     t4_waiters will be released
// --------------------------------------------------
void t4_waiter() {
    t4_l1.Acquire();
    t4_s1.V();		// Let the signaller know we're ready to wait
    printf("%s: Lock %s acquired, waiting on %s\n\n",currentThread->getName(),
	   t4_l1.getName(), t4_c1.getName());
    t4_c1.Wait(&t4_l1);
    printf("%s: freed from %s\n\n",currentThread->getName(), t4_c1.getName());
    t4_l1.Release();
    t4_done.V();
}


// --------------------------------------------------
// t2_signaller()
//     This thread will broadcast to the t4_c1 condition variable.
//     All t4_waiters will be released
// --------------------------------------------------
void t4_signaller() {

    // Don't broadcast until someone's waiting
    
    for ( int i = 0; i < 5 ; i++ ) 
	t4_s1.P();
    t4_l1.Acquire();
    printf("%s: Lock %s acquired, broadcasting %s\n\n",currentThread->getName(),
	   t4_l1.getName(), t4_c1.getName());
    t4_c1.Broadcast(&t4_l1);
    printf("%s: Releasing %s\n\n",currentThread->getName(), t4_l1.getName());
    t4_l1.Release();
    t4_done.V();
}
// --------------------------------------------------
// Test 5 - see TestSuite() for details
// --------------------------------------------------
Lock t5_l1("t5_l1\n");		// For mutual exclusion
Lock t5_l2("t5_l2\n");		// Second lock for the bad behavior
Condition t5_c1("t5_c1\n");	// The condition variable to test
Semaphore t5_s1("t5_s1\n",0);	// To make sure t5_t2 acquires the lock after
                                // t5_t1

// --------------------------------------------------
// t5_t1() -- test 5 thread 1
//     This thread will wait on a condition under t5_l1
// --------------------------------------------------
void t5_t1() {
    t5_l1.Acquire();
    t5_s1.V();	// release t5_t2
    printf("%s: Lock %s acquired, waiting on %s\n\n",currentThread->getName(),
	   t5_l1.getName(), t5_c1.getName());
    t5_c1.Wait(&t5_l1);
    printf("%s: Releasing Lock %s\n\n",currentThread->getName(),
	   t5_l1.getName());
    t5_l1.Release();
}

// --------------------------------------------------
// t5_t1() -- test 5 thread 1
//     This thread will wait on a t5_c1 condition under t5_l2, which is
//     a Fatal error
// --------------------------------------------------
void t5_t2() {
    t5_s1.P();	// Wait for t5_t1 to get into the monitor
    t5_l1.Acquire();
    t5_l2.Acquire();
    printf("%s: Lock %s acquired, signalling %s\n\n",currentThread->getName(),
	   t5_l2.getName(), t5_c1.getName());
    t5_c1.Signal(&t5_l2);
    printf("%s: Releasing Lock %s\n\n",currentThread->getName(),
	   t5_l2.getName());
    t5_l2.Release();
    printf("%s: Releasing Lock %s\n\n",currentThread->getName(),
	   t5_l1.getName());
    t5_l1.Release();
}

// --------------------------------------------------
// TestSuite()
//     This is the main thread of the test suite.  It runs the
//     following tests:
//
//       1.  Show that a thread trying to release a lock it does not
//       hold does not work
//
//       2.  Show that Signals are not stored -- a Signal with no
//       thread waiting is ignored
//
//       3.  Show that Signal only wakes 1 thread
//
//	 4.  Show that Broadcast wakes all waiting threads
//
//       5.  Show that Signalling a thread waiting under one lock
//       while holding another is a Fatal error
//
//     Fatal errors terminate the thread in question.
// --------------------------------------------------
void TestSuite() {
    Thread *t;
    char *name;
    int i;
    
    // Test 1

    printf("Starting Test 1\n\n");

    t = new Thread("t1_t1\n");
    t->Fork((VoidFunctionPtr)t1_t1,0);

    t = new Thread("t1_t2\n");
    t->Fork((VoidFunctionPtr)t1_t2,0);

    t = new Thread("t1_t3\n");
    t->Fork((VoidFunctionPtr)t1_t3,0);

    // Wait for Test 1 to complete
    for (  i = 0; i < 2; i++ )
	t1_done.P();

    // Test 2

    printf("Starting Test 2.  Note that it is an error if thread t2_t2\n\n");
    printf("completes\n\n");

    t = new Thread("t2_t1\n");
    t->Fork((VoidFunctionPtr)t2_t1,0);

    t = new Thread("t2_t2\n");
    t->Fork((VoidFunctionPtr)t2_t2,0);

    // Wait for Test 2 to complete
    t2_done.P();

    // Test 3

    printf("Starting Test 3\n\n");

    for (  i = 0 ; i < 5 ; i++ ) {
	name = new char [20];
	sprintf(name,"t3_waiter%d\n",i);
	t = new Thread(name);
	t->Fork((VoidFunctionPtr)t3_waiter,0);
    }
    t = new Thread("t3_signaller\n");
    t->Fork((VoidFunctionPtr)t3_signaller,0);

    // Wait for Test 3 to complete
    for (  i = 0; i < 2; i++ )
	t3_done.P();

    // Test 4

    printf("Starting Test 4\n\n");

    for (  i = 0 ; i < 5 ; i++ ) {
	name = new char [20];
	sprintf(name,"t4_waiter%d\n",i);
	t = new Thread(name);
	t->Fork((VoidFunctionPtr)t4_waiter,0);
    }
    t = new Thread("t4_signaller\n");
    t->Fork((VoidFunctionPtr)t4_signaller,0);

    // Wait for Test 4 to complete
    for (  i = 0; i < 6; i++ )
	t4_done.P();

    // Test 5

    printf("Starting Test 5.  Note that it is an error if thread t5_t1\n\n");
    printf("completes\n\n");

    t = new Thread("t5_t1\n");
    t->Fork((VoidFunctionPtr)t5_t1,0);

    t = new Thread("t5_t2\n");
    t->Fork((VoidFunctionPtr)t5_t2,0);

}
#endif
